diff --git a/infra/main.bicep b/infra/main.bicep index 17ae3dbc..baf98ce8 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -363,6 +363,10 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.15.0' = if (enable adminPassword: vmAdminPassword ?? 'JumpboxAdminP@ssw0rd1234!' tags: allTags zone: 0 + // SFI: enable system-assigned managed identity on the jumpbox VM. Required so + // the Azure Monitor Agent can authenticate to the Log Analytics workspace and + // honor the SecurityAuditEvents data collection rule association. + managedIdentities: { systemAssigned: true } imageReference: { offer: 'WindowsServer' publisher: 'MicrosoftWindowsServer' @@ -409,6 +413,148 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.15.0' = if (enable } ] enableTelemetry: enableTelemetry + // SFI: associate the SecurityAuditEvents data collection rule with the + // jumpbox VM via the Azure Monitor Agent extension. Routes Windows audit + // success / audit failure events to Log Analytics. Gated on the same + // (enablePrivateNetworking && enableMonitoring) expression as the DCR + // module so the dereference of windowsVmDataCollectionRules!.outputs + // stays safe even if the outer jumpbox VM gate ever changes. + extensionMonitoringAgentConfig: (enablePrivateNetworking && enableMonitoring) + ? { + enabled: true + tags: allTags + dataCollectionRuleAssociations: [ + { + name: 'send-${logAnalyticsWorkspaceResourceName}' + dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId + } + ] + } + : null + } +} + +// SFI: data collection rule that captures Windows Security audit success and +// audit failure events from the jumpbox VM and routes them to Log Analytics +// via the Microsoft-Event stream. The xPath filter uses the Windows +// audit Keywords bitmask (0x30000000000000 = AuditSuccess|AuditFailure) and +// excludes EventID 4624 (successful logon) because it is extremely +// high-volume. Also collects a small set of Windows performance counters via +// Microsoft-Perf for the jumpbox so the same DCR provides basic VM health +// signal. The SecurityEvent / Perf tables are auto-provisioned by Azure +// Monitor on first ingestion via the DCR; no legacy OMSGallery/Security +// solution is needed. +var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' +var dataCollectionRulesLocation = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.location + : logAnalyticsWorkspace!.outputs.location +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: allTags + enableTelemetry: enableTelemetry + location: dataCollectionRulesLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + windowsEventLogs: [ + { + name: 'SecurityAuditEvents' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' + ] + } + ] + performanceCounters: [ + { + name: 'perfCounterDataSource60' + 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' + ] + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: dcrLogAnalyticsDestinationName + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Event' + ] + destinations: [ + dcrLogAnalyticsDestinationName + ] + } + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + dcrLogAnalyticsDestinationName + ] + } + ] + } } } @@ -480,6 +626,8 @@ module storageAccount 'br/public:avm/res/storage/storage-account:0.20.0' = { location: solutionLocation managedIdentities: { systemAssigned: true } minimumTlsVersion: 'TLS1_2' + // SFI: enable infrastructure (double) encryption at rest + requireInfrastructureEncryption: true enableTelemetry: enableTelemetry tags: allTags accessTier: 'Hot' @@ -598,6 +746,8 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.15.0' = { location: cosmosLocation tags: allTags enableTelemetry: enableTelemetry + // SFI: enable system-assigned managed identity for Cosmos DB account + managedIdentities: { systemAssigned: true } sqlDatabases: [ { name: cosmosDatabaseName @@ -1147,6 +1297,11 @@ module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.11. ] enableTelemetry: enableTelemetry publicNetworkAccess: 'Enabled' // Always enabled for Container Apps Environment + // SFI: enable mTLS / end-to-end encryption between revisions within the + // Container Apps environment (Container Apps equivalent of App Service's + // endToEndEncryptionEnabled). Applies to Microsoft.App/managedEnvironments + // peerTrafficConfiguration.encryption.enabled. + peerTrafficEncryption: true // <========== WAF related parameters diff --git a/infra/main.json b/infra/main.json index 4807e455..df3ac114 100644 --- a/infra/main.json +++ b/infra/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "13087590133917597872" + "version": "0.42.1.51946", + "templateHash": "16235959711463268871" } }, "parameters": { @@ -271,6 +271,8 @@ "applicationInsightsResourceName": "[format('appi-{0}', variables('solutionSuffix'))]", "bastionHostName": "[format('bas-{0}', variables('solutionSuffix'))]", "jumpboxVmName": "[take(format('vm-jumpbox-{0}', variables('solutionSuffix')), 15)]", + "dataCollectionRulesResourceName": "[format('dcr-{0}', variables('solutionSuffix'))]", + "dcrLogAnalyticsDestinationName": "[format('la-{0}-destination', variables('logAnalyticsWorkspaceResourceName'))]", "processBlobContainerName": "processes", "processQueueName": "processes-queue", "privateDnsZones": [ @@ -4715,8 +4717,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "4604761290796021104" + "version": "0.42.1.51946", + "templateHash": "2245351167779444314" } }, "definitions": { @@ -8874,6 +8876,11 @@ "zone": { "value": 0 }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "imageReference": { "value": { "offer": "WindowsServer", @@ -8912,7 +8919,8 @@ }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" - } + }, + "extensionMonitoringAgentConfig": "[if(and(parameters('enablePrivateNetworking'), parameters('enableMonitoring')), createObject('value', createObject('enabled', true(), 'tags', variables('allTags'), 'dataCollectionRuleAssociations', createArray(createObject('name', format('send-{0}', variables('logAnalyticsWorkspaceResourceName')), 'dataCollectionRuleResourceId', reference('windowsVmDataCollectionRules').outputs.resourceId.value)))), createObject('value', null()))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -17166,7 +17174,1337 @@ }, "dependsOn": [ "logAnalyticsWorkspace", - "virtualNetwork" + "virtualNetwork", + "windowsVmDataCollectionRules" + ] + }, + "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": "[variables('allTags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "location": "[if(variables('useExistingLogAnalytics'), createObject('value', reference('existingLogAnalyticsWorkspace', '2020-08-01', 'full').location), createObject('value', reference('logAnalyticsWorkspace').outputs.location.value))]", + "dataCollectionRuleProperties": { + "value": { + "kind": "Windows", + "dataSources": { + "windowsEventLogs": [ + { + "name": "SecurityAuditEvents", + "streams": [ + "Microsoft-Event" + ], + "xPathQueries": [ + "Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]" + ] + } + ], + "performanceCounters": [ + { + "name": "perfCounterDataSource60", + "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" + ] + } + ] + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value)]", + "name": "[variables('dcrLogAnalyticsDestinationName')]" + } + ] + }, + "dataFlows": [ + { + "streams": [ + "Microsoft-Event" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ] + }, + { + "streams": [ + "Microsoft-Perf" + ], + "destinations": [ + "[variables('dcrLogAnalyticsDestinationName')]" + ] + } + ] + } + } + }, + "template": { + "$schema": "https://schema.management.azure.com/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": [ + "existingLogAnalyticsWorkspace", + "logAnalyticsWorkspace" ] }, "avmPrivateDnsZones": { @@ -20367,6 +21705,9 @@ "minimumTlsVersion": { "value": "TLS1_2" }, + "requireInfrastructureEncryption": { + "value": true + }, "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, @@ -26135,8 +27476,8 @@ }, "dependsOn": [ "appIdentity", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", "virtualNetwork" ] }, @@ -26162,6 +27503,11 @@ "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, "sqlDatabases": { "value": [ { @@ -30103,8 +31449,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "13516349791985095953" + "version": "0.42.1.51946", + "templateHash": "16866311185741009453" } }, "definitions": { @@ -33854,8 +35200,8 @@ "dependsOn": [ "aiFoundryAiServices", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)]", "virtualNetwork" ] }, @@ -33892,8 +35238,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.43.8.12551", - "templateHash": "17583277036649944863" + "version": "0.42.1.51946", + "templateHash": "16351752584270870112" } }, "parameters": { @@ -38385,6 +39731,9 @@ "publicNetworkAccess": { "value": "Enabled" }, + "peerTrafficEncryption": { + "value": true + }, "platformReservedCidr": { "value": "172.17.17.0/24" }, diff --git a/infra/main_custom.bicep b/infra/main_custom.bicep index fd17ec47..a1c6610e 100644 --- a/infra/main_custom.bicep +++ b/infra/main_custom.bicep @@ -341,6 +341,10 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.15.0' = if (enable adminPassword: vmAdminPassword ?? 'JumpboxAdminP@ssw0rd1234!' tags: allTags zone: 0 + // SFI: enable system-assigned managed identity on the jumpbox VM. Required so + // the Azure Monitor Agent can authenticate to the Log Analytics workspace and + // honor the SecurityAuditEvents data collection rule association. + managedIdentities: { systemAssigned: true } imageReference: { offer: 'WindowsServer' publisher: 'MicrosoftWindowsServer' @@ -387,6 +391,148 @@ module jumpboxVM 'br/public:avm/res/compute/virtual-machine:0.15.0' = if (enable } ] enableTelemetry: enableTelemetry + // SFI: associate the SecurityAuditEvents data collection rule with the + // jumpbox VM via the Azure Monitor Agent extension. Routes Windows audit + // success / audit failure events to Log Analytics. Gated on the same + // (enablePrivateNetworking && enableMonitoring) expression as the DCR + // module so the dereference of windowsVmDataCollectionRules!.outputs + // stays safe even if the outer jumpbox VM gate ever changes. + extensionMonitoringAgentConfig: (enablePrivateNetworking && enableMonitoring) + ? { + enabled: true + tags: allTags + dataCollectionRuleAssociations: [ + { + name: 'send-${logAnalyticsWorkspaceResourceName}' + dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId + } + ] + } + : null + } +} + +// SFI: data collection rule that captures Windows Security audit success and +// audit failure events from the jumpbox VM and routes them to Log Analytics +// via the Microsoft-Event stream. The xPath filter uses the Windows +// audit Keywords bitmask (0x30000000000000 = AuditSuccess|AuditFailure) and +// excludes EventID 4624 (successful logon) because it is extremely +// high-volume. Also collects a small set of Windows performance counters via +// Microsoft-Perf for the jumpbox so the same DCR provides basic VM health +// signal. The SecurityEvent / Perf tables are auto-provisioned by Azure +// Monitor on first ingestion via the DCR; no legacy OMSGallery/Security +// solution is needed. +var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' +var dataCollectionRulesLocation = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.location + : logAnalyticsWorkspace!.outputs.location +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: allTags + enableTelemetry: enableTelemetry + location: dataCollectionRulesLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + windowsEventLogs: [ + { + name: 'SecurityAuditEvents' + streams: [ + 'Microsoft-Event' + ] + xPathQueries: [ + 'Security!*[System[(band(Keywords,13510798882111488)) and (EventID != 4624)]]' + ] + } + ] + performanceCounters: [ + { + name: 'perfCounterDataSource60' + 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' + ] + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: dcrLogAnalyticsDestinationName + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Event' + ] + destinations: [ + dcrLogAnalyticsDestinationName + ] + } + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + dcrLogAnalyticsDestinationName + ] + } + ] + } } } @@ -458,6 +604,8 @@ module storageAccount 'br/public:avm/res/storage/storage-account:0.20.0' = { location: solutionLocation managedIdentities: { systemAssigned: true } minimumTlsVersion: 'TLS1_2' + // SFI: enable infrastructure (double) encryption at rest + requireInfrastructureEncryption: true enableTelemetry: enableTelemetry tags: allTags accessTier: 'Hot' @@ -563,6 +711,8 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.15.0' = { location: cosmosLocation tags: allTags enableTelemetry: enableTelemetry + // SFI: enable system-assigned managed identity for Cosmos DB account + managedIdentities: { systemAssigned: true } sqlDatabases: [ { name: cosmosDatabaseName @@ -697,6 +847,8 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.9.1' = softDeletePolicyStatus: 'disabled' tags: allTags networkRuleBypassOptions: 'AzureServices' + // SFI: enable system-assigned managed identity for the container registry + managedIdentities: { systemAssigned: true } roleAssignments: [ { roleDefinitionIdOrName: acrPullRole @@ -1100,6 +1252,11 @@ module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.11. ] enableTelemetry: enableTelemetry publicNetworkAccess: 'Enabled' // Always enabled for Container Apps Environment + // SFI: enable mTLS / end-to-end encryption between revisions within the + // Container Apps environment (Container Apps equivalent of App Service's + // endToEndEncryptionEnabled). Applies to Microsoft.App/managedEnvironments + // peerTrafficConfiguration.encryption.enabled. + peerTrafficEncryption: true // <========== WAF related parameters diff --git a/infra/modules/storageAccount.bicep b/infra/modules/storageAccount.bicep index 9c9c91f2..e49a6828 100644 --- a/infra/modules/storageAccount.bicep +++ b/infra/modules/storageAccount.bicep @@ -61,6 +61,9 @@ module storageAccount 'br/public:avm/res/storage/storage-account:0.26.2' = { allowBlobPublicAccess: false allowSharedKeyAccess: false allowCrossTenantReplication: false + // SFI: enable infrastructure (double) encryption at rest + requireInfrastructureEncryption: true + keyType: 'Service' blobServices: { deleteRetentionPolicyEnabled: true deleteRetentionPolicyDays: 7