Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/CustomizingAzdParameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ By default this template will use the environment name as the prefix to prevent
| `AZURE_ENV_ENABLE_TELEMETRY` | boolean | `true` | Enable or disable telemetry collection for the deployment. |
| `AZURE_ENV_VM_ADMIN_USERNAME` | string | `<Set when enablePrivateNetworking=true>` | Admin username for the jumpbox VM when private networking is enabled. |
| `AZURE_ENV_VM_ADMIN_PASSWORD` | string | `<Set when enablePrivateNetworking=true>` | Admin password for the jumpbox VM when private networking is enabled. |
| `AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID` | string | Guide to get your [Existing Workspace ID](/docs/re-use-log-analytics.md) | Reuses an existing Log Analytics Workspace instead of provisioning a new one. |


## How to Set a Parameter
Expand Down
12 changes: 11 additions & 1 deletion docs/DeploymentGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ For **production deployments**, the repository also provides [`main.waf.paramete
* Use the default `main.parameters.json` file for a **sandbox/dev environment**
* For a **WAF-aligned, production-ready deployment**, copy the contents of `main.waf.parameters.json` into `main.parameters.json` before running `azd up`

### VM Credentials Configuration
### Configuration Options

#### VM Credentials Configuration

By default, the solution sets the VM administrator username and password from environment variables.

Expand All @@ -33,6 +35,14 @@ azd env set AZURE_ENV_VM_ADMIN_USERNAME <your-username>
azd env set AZURE_ENV_VM_ADMIN_PASSWORD <your-password>
```

#### Additional Configuration

<details>
<summary><b>Reusing an Existing Log Analytics Workspace</b></summary>

Guide to get your [Existing Workspace ID](/docs/re-use-log-analytics.md)
</details>

> [!TIP]
> Always review and adjust parameter values (such as region, capacity, security settings and log analytics workspace configuration) to match your organization’s requirements before deploying. For production, ensure you have sufficient quota and follow the principle of least privilege for all identities and role assignments.

Expand Down
Binary file added docs/images/re_use_log/logAnalytics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/re_use_log/logAnalyticsJson.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/re_use_log/logAnalyticsList.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions docs/re-use-log-analytics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[← Back to *DEPLOYMENT* guide](/docs/DeploymentGuide.md#deployment-options--steps)

# Reusing an Existing Log Analytics Workspace
To configure your environment to use an existing Log Analytics Workspace, follow these steps:
---
### 1. Go to Azure Portal
Go to https://portal.azure.com

### 2. Search for Log Analytics
In the search bar at the top, type "Log Analytics workspaces" and click on it and click on the workspace you want to use.

![alt text](../docs/images/re_use_log/logAnalyticsList.png)

### 3. Copy Resource ID
In the Overview pane, Click on JSON View

![alt text](../docs/images/re_use_log/logAnalytics.png)

Copy Resource ID that is your Workspace ID

![alt text](../docs/images/re_use_log/logAnalyticsJson.png)

### 4. Set the Workspace ID in Your Environment
Run the following command in your terminal
```bash
azd env set AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID '<Existing Log Analytics Workspace Id>'
```
Replace `<Existing Log Analytics Workspace Id>` with the value obtained from Step 3.

### 5. Continue Deployment
Proceed with the next steps in the [deployment guide](/docs/DeploymentGuide.md#deployment-options--steps).
26 changes: 18 additions & 8 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ param vmSize string = 'Standard_DS2_v2' // Default VM size
@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)

@description('Optional. Resource ID of an existing Log Analytics Workspace.')
param existingLogAnalyticsWorkspaceId string = ''

var solutionSuffix = toLower(trim(replace(
replace(
replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''),
Expand Down Expand Up @@ -178,7 +181,7 @@ module network 'modules/network.bicep' = if (enablePrivateNetworking) {
name: take('module.network.${solutionSuffix}', 64)
params: {
resourcesName: resourceGroupName
logAnalyticsWorkSpaceResourceId: logAnalyticsWorkspace!.outputs.resourceId
logAnalyticsWorkSpaceResourceId: logAnalyticsWorkspaceResourceId
vmAdminUsername: empty(vmAdminUsername) ? 'JumpboxAdminUser' : vmAdminUsername
vmAdminPassword: empty(vmAdminPassword) ? 'JumpboxAdminP@ssw0rd1234!' : vmAdminPassword
vmSize: empty(vmSize) ? 'Standard_DS2_v2' : vmSize
Expand Down Expand Up @@ -456,7 +459,7 @@ module keyvault 'br/public:avm/res/key-vault/vault:0.12.1' = {
enableSoftDelete: true
enablePurgeProtection: enablePurgeProtection
softDeleteRetentionInDays: 7
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : []
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : []
// WAF aligned configuration for Private Networking
privateEndpoints: enablePrivateNetworking
? [
Expand Down Expand Up @@ -842,16 +845,18 @@ module webServerFarm 'br/public:avm/res/web/serverfarm:0.5.0' = {
reserved: true
kind: 'linux'
// WAF aligned configuration for Monitoring
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null
// WAF aligned configuration for Scalability
skuName: enableScalability || enableRedundancy ? 'P1v3' : 'B3'
skuCapacity: enableScalability ? 3 : 1
zoneRedundant: enableRedundancy ? true : false
}
}

// Extracts subscription, resource group, and workspace name from the resource ID when using an existing Log Analytics workspace
var useExistingLogAnalytics = !empty(existingLogAnalyticsWorkspaceId)
var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}'
module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.12.0' = if (enableMonitoring) {
module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.12.0' = if (enableMonitoring && !useExistingLogAnalytics) {
name: take('avm.res.operational-insights.workspace.${logAnalyticsWorkspaceResourceName}', 64)
params: {
name: logAnalyticsWorkspaceResourceName
Expand Down Expand Up @@ -909,6 +914,11 @@ module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0
}
}

// Log Analytics workspace ID)
var logAnalyticsWorkspaceResourceId = useExistingLogAnalytics
? existingLogAnalyticsWorkspaceId
: logAnalyticsWorkspace!.outputs.resourceId

var ApplicationInsightsName = 'appi-${solutionSuffix}'
module applicationInsights 'br/public:avm/res/insights/component:0.6.0' = if (enableMonitoring) {
name: take('avm.res.insights.component.${ApplicationInsightsName}', 64)
Expand All @@ -920,8 +930,8 @@ module applicationInsights 'br/public:avm/res/insights/component:0.6.0' = if (en
applicationType: 'web'
// Tags (align with organizational tagging policy)
// WAF aligned configuration for Monitoring
workspaceResourceId: enableMonitoring ? logAnalyticsWorkspace!.outputs.resourceId : ''
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null
workspaceResourceId: enableMonitoring ? logAnalyticsWorkspaceResourceId : ''
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null
tags: {
'hidden-link:${resourceId('Microsoft.Web/sites',ApplicationInsightsName)}': 'Resource'
}
Expand Down Expand Up @@ -1013,8 +1023,8 @@ module webSite 'modules/web-sites.bicep' = {
applicationInsightResourceId: enableMonitoring ? applicationInsights!.outputs.resourceId : null
}
]
diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] : null

diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null
// WAF aligned configuration for Private Networking
vnetRouteAllEnabled: enablePrivateNetworking ? true : false
vnetImagePullEnabled: enablePrivateNetworking ? true : false
Expand Down
32 changes: 19 additions & 13 deletions infra/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "0.37.4.10188",
"templateHash": "4794754891660644835"
"templateHash": "464900527149069806"
}
},
"parameters": {
Expand Down Expand Up @@ -203,6 +203,13 @@
"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."
}
},
"existingLogAnalyticsWorkspaceId": {
"type": "string",
"defaultValue": "",
"metadata": {
"description": "Optional. Resource ID of an existing Log Analytics Workspace."
}
},
"createdBy": {
"type": "string",
"defaultValue": "[if(contains(deployer(), 'userPrincipalName'), split(deployer().userPrincipalName, '@')[0], deployer().objectId)]",
Expand Down Expand Up @@ -291,6 +298,7 @@
"aihubworkspaceName": "[format('hub-{0}', variables('solutionSuffix'))]",
"aiProjectworkspaceName": "[format('proj-{0}', variables('solutionSuffix'))]",
"webServerFarmResourceName": "[format('asp-{0}', variables('solutionSuffix'))]",
"useExistingLogAnalytics": "[not(empty(parameters('existingLogAnalyticsWorkspaceId')))]",
"logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]",
"ApplicationInsightsName": "[format('appi-{0}', variables('solutionSuffix'))]",
"webSiteResourceName": "[format('app-{0}', variables('solutionSuffix'))]"
Expand Down Expand Up @@ -1027,9 +1035,7 @@
"resourcesName": {
"value": "[variables('resourceGroupName')]"
},
"logAnalyticsWorkSpaceResourceId": {
"value": "[reference('logAnalyticsWorkspace').outputs.resourceId.value]"
},
"logAnalyticsWorkSpaceResourceId": "[if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value))]",
"vmAdminUsername": "[if(empty(parameters('vmAdminUsername')), createObject('value', 'JumpboxAdminUser'), createObject('value', parameters('vmAdminUsername')))]",
"vmAdminPassword": "[if(empty(parameters('vmAdminPassword')), createObject('value', 'JumpboxAdminP@ssw0rd1234!'), createObject('value', parameters('vmAdminPassword')))]",
"vmSize": "[if(empty(parameters('vmSize')), createObject('value', 'Standard_DS2_v2'), createObject('value', parameters('vmSize')))]",
Expand Down Expand Up @@ -25722,9 +25728,9 @@
}
},
"dependsOn": [
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageFile)]",
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]",
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageDfs)]",
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]",
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageFile)]",
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]",
"network",
"userAssignedIdentity"
Expand Down Expand Up @@ -28727,7 +28733,7 @@
"softDeleteRetentionInDays": {
"value": 7
},
"diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', createArray()))]",
"diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value)))), createObject('value', createArray()))]",
"privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-{0}', variables('keyVaultName')), 'customNetworkInterfaceName', format('nic-{0}', variables('keyVaultName')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('name', 'vault-dns-zone-group', 'privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').keyVault)).outputs.resourceId.value))), 'service', 'vault', 'subnetResourceId', reference('network').outputs.subnetPrivateEndpointsResourceId.value))), createObject('value', createArray()))]",
"roleAssignments": {
"value": [
Expand Down Expand Up @@ -41596,8 +41602,8 @@
}
},
"dependsOn": [
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').notebook)]",
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').machineLearningServices)]",
"[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').notebook)]",
"azOpenAI",
"azSearchService",
"existingOpenAI",
Expand Down Expand Up @@ -46042,7 +46048,7 @@
"kind": {
"value": "linux"
},
"diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]",
"diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value)))), createObject('value', null()))]",
"skuName": "[if(or(parameters('enableScalability'), parameters('enableRedundancy')), createObject('value', 'P1v3'), createObject('value', 'B3'))]",
"skuCapacity": "[if(parameters('enableScalability'), createObject('value', 3), createObject('value', 1))]",
"zoneRedundant": "[if(parameters('enableRedundancy'), createObject('value', true()), createObject('value', false()))]"
Expand Down Expand Up @@ -46586,7 +46592,7 @@
]
},
"logAnalyticsWorkspace": {
"condition": "[parameters('enableMonitoring')]",
"condition": "[and(parameters('enableMonitoring'), not(variables('useExistingLogAnalytics')))]",
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-01",
"name": "[take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)]",
Expand Down Expand Up @@ -49714,8 +49720,8 @@
"applicationType": {
"value": "web"
},
"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()))]",
"workspaceResourceId": "[if(parameters('enableMonitoring'), if(variables('useExistingLogAnalytics'), createObject('value', parameters('existingLogAnalyticsWorkspaceId')), createObject('value', reference('logAnalyticsWorkspace').outputs.resourceId.value)), createObject('value', ''))]",
"diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value)))), createObject('value', null()))]",
"tags": {
"value": {
"[format('hidden-link:{0}', resourceId('Microsoft.Web/sites', variables('ApplicationInsightsName')))]": "Resource"
Expand Down Expand Up @@ -50509,7 +50515,7 @@
}
]
},
"diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('logAnalyticsWorkspace').outputs.resourceId.value))), createObject('value', null()))]",
"diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value)))), createObject('value', null()))]",
"vnetRouteAllEnabled": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]",
"vnetImagePullEnabled": "[if(parameters('enablePrivateNetworking'), createObject('value', true()), createObject('value', false()))]",
"virtualNetworkSubnetId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference('network').outputs.subnetWebResourceId.value), createObject('value', null()))]",
Expand Down
3 changes: 3 additions & 0 deletions infra/main.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
},
"enableTelemetry": {
"value": "${AZURE_ENV_ENABLE_TELEMETRY}"
},
"existingLogAnalyticsWorkspaceId": {
"value": "${AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID}"
}
}
}
3 changes: 3 additions & 0 deletions infra/main.waf.parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
},
"virtualMachineAdminPassword": {
"value": "${AZURE_ENV_VM_ADMIN_PASSWORD}"
},
"existingLogAnalyticsWorkspaceId": {
"value": "${AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID}"
}
}
}