diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2589d21..35b6033 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,21 +1,21 @@ -# Contributing to Microsoft Learning Repositories - -MCT contributions are a key part of keeping the lab and demo content current as the Azure platform changes. We want to make it as easy as possible for you to contribute changes to the lab files. Here are a few guidelines to keep in mind as you contribute changes. - -## GitHub Use & Purpose - -Microsoft Learning is using GitHub to publish the lab steps and lab scripts for courses that cover cloud services like Azure. Using GitHub allows the course’s authors and MCTs to keep the lab content current with Azure platform changes. Using GitHub allows the MCTs to provide feedback and suggestions for lab changes, and then the course authors can update lab steps and scripts quickly and relatively easily. - -> When you prepare to teach these courses, you should ensure that you are using the latest lab steps and scripts by downloading the appropriate files from GitHub. GitHub should not be used to discuss technical content in the course, or how to prep. It should only be used to address changes in the labs. - -It is strongly recommended that MCTs and Partners access these materials and in turn, provide them separately to students. Pointing students directly to GitHub to access Lab steps as part of an ongoing class will require them to access yet another UI as part of the course, contributing to a confusing experience for the student. An explanation to the student regarding why they are receiving separate Lab instructions can highlight the nature of an always-changing cloud-based interface and platform. Microsoft Learning support for accessing files on GitHub and support for navigation of the GitHub site is limited to MCTs teaching this course only. - -> As an alternative to pointing students directly to the GitHub repository, you can point students to the GitHub Pages website to view the lab instructions. The URL for the GitHub Pages website can be found at the top of the repository. - -To address general comments about the course and demos, or how to prepare for a course delivery, please use the existing MCT forums. - -## Additional Resources - -A user guide has been provided for MCTs who are new to GitHub. It provides steps for connecting to GitHub, downloading and printing course materials, updating the scripts that students use in labs, and explaining how you can help ensure that this course’s content remains current. - - +# Contributing to Microsoft Learning Repositories + +MCT contributions are a key part of keeping the lab and demo content current as the Azure platform changes. We want to make it as easy as possible for you to contribute changes to the lab files. Here are a few guidelines to keep in mind as you contribute changes. + +## GitHub Use & Purpose + +Microsoft Learning is using GitHub to publish the lab steps and lab scripts for courses that cover cloud services like Azure. Using GitHub allows the course’s authors and MCTs to keep the lab content current with Azure platform changes. Using GitHub allows the MCTs to provide feedback and suggestions for lab changes, and then the course authors can update lab steps and scripts quickly and relatively easily. + +> When you prepare to teach these courses, you should ensure that you are using the latest lab steps and scripts by downloading the appropriate files from GitHub. GitHub should not be used to discuss technical content in the course, or how to prep. It should only be used to address changes in the labs. + +It is strongly recommended that MCTs and Partners access these materials and in turn, provide them separately to students. Pointing students directly to GitHub to access Lab steps as part of an ongoing class will require them to access yet another UI as part of the course, contributing to a confusing experience for the student. An explanation to the student regarding why they are receiving separate Lab instructions can highlight the nature of an always-changing cloud-based interface and platform. Microsoft Learning support for accessing files on GitHub and support for navigation of the GitHub site is limited to MCTs teaching this course only. + +> As an alternative to pointing students directly to the GitHub repository, you can point students to the GitHub Pages website to view the lab instructions. The URL for the GitHub Pages website can be found at the top of the repository. + +To address general comments about the course and demos, or how to prepare for a course delivery, please use the existing MCT forums. + +## Additional Resources + +A user guide has been provided for MCTs who are new to GitHub. It provides steps for connecting to GitHub, downloading and printing course materials, updating the scripts that students use in labs, and explaining how you can help ensure that this course’s content remains current. + + diff --git a/Allfiles/Labs/02/azuredeploy.parameters.json b/Allfiles/Labs/02/azuredeploy.parameters.json index e5d28cb..a30d905 100644 --- a/Allfiles/Labs/02/azuredeploy.parameters.json +++ b/Allfiles/Labs/02/azuredeploy.parameters.json @@ -1,12 +1,12 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "listOfAllowedLocations": { - "type": "Array", - "value": [ - "UK South" - ] - } - } +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "listOfAllowedLocations": { + "type": "Array", + "value": [ + "UK South" + ] + } + } } \ No newline at end of file diff --git a/Allfiles/Labs/03/main.bicep b/Allfiles/Labs/03/main.bicep index fff843d..1f3e34f 100644 --- a/Allfiles/Labs/03/main.bicep +++ b/Allfiles/Labs/03/main.bicep @@ -1,79 +1,79 @@ -@description('Specifies the name of the key vault.') -param keyVaultName string - -@description('Specifies the Azure location where the key vault should be created.') -param location string = resourceGroup().location - -@description('Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault.') -param enabledForDeployment bool = false - -@description('Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys.') -param enabledForDiskEncryption bool = false - -@description('Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault.') -param enabledForTemplateDeployment bool = false - -@description('Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet.') -param tenantId string = subscription().tenantId - -@description('Specifies the object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets.') -param objectId string - -@description('Specifies the permissions to keys in the vault. Valid values are: all, encrypt, decrypt, wrapKey, unwrapKey, sign, verify, get, list, create, update, import, delete, backup, restore, recover, and purge.') -param keysPermissions array = [ - 'list' - 'get' - 'create' - 'delete' - 'sign' -] - -@description('Specifies the permissions to secrets in the vault. Valid values are: all, get, list, set, delete, backup, restore, recover, and purge.') -param secretsPermissions array = [ - 'all' -] - -@description('Specifies whether the key vault is a standard vault or a premium vault.') -@allowed([ - 'standard' - 'premium' -]) -param skuName string = 'standard' - -@description('Specifies the name of the secret that you want to create.') -param secretName string - -@description('Specifies the value of the secret that you want to create.') -@secure() -param secretValue string - -resource kv 'Microsoft.KeyVault/vaults@2021-11-01-preview' = { - name: keyVaultName - location: location - properties: { - enabledForDeployment: enabledForDeployment - enabledForDiskEncryption: enabledForDiskEncryption - enabledForTemplateDeployment: enabledForTemplateDeployment - tenantId: tenantId - enableSoftDelete: true - softDeleteRetentionInDays: 90 - accessPolicies: [ - { - objectId: objectId - tenantId: tenantId - permissions: { - keys: keysPermissions - secrets: secretsPermissions - } - } - ] - sku: { - name: skuName - family: 'A' - } - networkAcls: { - defaultAction: 'Allow' - bypass: 'AzureServices' - } - } -} +@description('Specifies the name of the key vault.') +param keyVaultName string + +@description('Specifies the Azure location where the key vault should be created.') +param location string = resourceGroup().location + +@description('Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault.') +param enabledForDeployment bool = false + +@description('Specifies whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys.') +param enabledForDiskEncryption bool = false + +@description('Specifies whether Azure Resource Manager is permitted to retrieve secrets from the key vault.') +param enabledForTemplateDeployment bool = false + +@description('Specifies the Azure Active Directory tenant ID that should be used for authenticating requests to the key vault. Get it by using Get-AzSubscription cmdlet.') +param tenantId string = subscription().tenantId + +@description('Specifies the object ID of a user, service principal or security group in the Azure Active Directory tenant for the vault. The object ID must be unique for the list of access policies. Get it by using Get-AzADUser or Get-AzADServicePrincipal cmdlets.') +param objectId string + +@description('Specifies the permissions to keys in the vault. Valid values are: all, encrypt, decrypt, wrapKey, unwrapKey, sign, verify, get, list, create, update, import, delete, backup, restore, recover, and purge.') +param keysPermissions array = [ + 'list' + 'get' + 'create' + 'delete' + 'sign' +] + +@description('Specifies the permissions to secrets in the vault. Valid values are: all, get, list, set, delete, backup, restore, recover, and purge.') +param secretsPermissions array = [ + 'all' +] + +@description('Specifies whether the key vault is a standard vault or a premium vault.') +@allowed([ + 'standard' + 'premium' +]) +param skuName string = 'standard' + +@description('Specifies the name of the secret that you want to create.') +param secretName string + +@description('Specifies the value of the secret that you want to create.') +@secure() +param secretValue string + +resource kv 'Microsoft.KeyVault/vaults@2021-11-01-preview' = { + name: keyVaultName + location: location + properties: { + enabledForDeployment: enabledForDeployment + enabledForDiskEncryption: enabledForDiskEncryption + enabledForTemplateDeployment: enabledForTemplateDeployment + tenantId: tenantId + enableSoftDelete: true + softDeleteRetentionInDays: 90 + accessPolicies: [ + { + objectId: objectId + tenantId: tenantId + permissions: { + keys: keysPermissions + secrets: secretsPermissions + } + } + ] + sku: { + name: skuName + family: 'A' + } + networkAcls: { + defaultAction: 'Allow' + bypass: 'AzureServices' + } + } +} diff --git a/Allfiles/Labs/04/main.bicep b/Allfiles/Labs/04/main.bicep index 0fcca33..dab4f94 100644 --- a/Allfiles/Labs/04/main.bicep +++ b/Allfiles/Labs/04/main.bicep @@ -1,364 +1,364 @@ -@description('Username for the Virtual Machine.') -param adminUsername string - -@description('Password for the Virtual Machine.') -@minLength(12) -@secure() -param adminPassword string - -@description('Unique DNS Name for the Public IP used to access the first Virtual Machine.') -param dnsLabelPrefix1 string = toLower('${vmName1}-${uniqueString(resourceGroup().id, vmName1)}') - -@description('Unique DNS Name for the Public IP used to access the second Virtual Machine.') -param dnsLabelPrefix2 string = toLower('${vmName2}-${uniqueString(resourceGroup().id, vmName2)}') - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName1 string = 'myPublicIP1' - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName2 string = 'myPublicIP2' - -@description('Allocation method for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Dynamic' - 'Static' -]) -param publicIPAllocationMethod string = 'Dynamic' - -@description('SKU for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Basic' - 'Standard' -]) -param publicIpSku string = 'Basic' - -@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') -@allowed([ -'2022-datacenter' -'2022-datacenter-azure-edition' -'2022-datacenter-azure-edition-core' -]) -param OSVersion string = '2022-datacenter-azure-edition-core' - -@description('Size of the virtual machine.') -param vmSize string = 'Standard_D2s_v3' - -@description('Location for all resources.') -param location string = resourceGroup().location - -@description('Name of the virtual machine.') -param vmName1 string = 'myVMWeb' - -@description('Name of the virtual machine.') -param vmName2 string = 'myVMMgmt' - -var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' -var nicName1 = 'nic1' -var nicName2 = 'nic2' -var addressPrefix = '10.0.0.0/16' -var subnetName = 'default' -var subnetPrefix = '10.0.0.0/24' -var virtualNetworkName = 'myVirtualNetwork' -var networkSecurityGroupName = 'myNsg' -var applicationSecurityGroupName1 = 'myAsgWebServers' -var applicationSecurityGroupName2 = 'myAsgMgmtServers' - - -resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { - name: storageAccountName - location: location - sku: { - name: 'Standard_LRS' - } - kind: 'Storage' -} - -resource pip1 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName1 - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix1 - } - } -} - -resource pip2 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName2 - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix2 - } - } -} - -resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { - name: networkSecurityGroupName - location: location - properties: { - securityRules: [ - { - name: 'Allow-RDP-All' - properties: { - priority: 100 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '3389' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'Allow-WEB-HTTP' - properties: { - priority: 200 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '80' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'Allow-WEB-HTTPS' - properties: { - priority: 300 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '443' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - ] - } -} - -resource applicationSecurityGroup1 'Microsoft.Network/applicationSecurityGroups@2022-05-01' = { - name: applicationSecurityGroupName1 - location: location - - properties: {} -} - -resource applicationSecurityGroup2 'Microsoft.Network/applicationSecurityGroups@2022-05-01' = { - name: applicationSecurityGroupName2 - location: location - - properties: {} -} - -resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: subnetName - properties: { - addressPrefix: subnetPrefix - networkSecurityGroup: { - id: networkSecurityGroup.id - } - } - } - ] - } -} - -resource nic1 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nicName1 - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip1.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnetName) - } - applicationSecurityGroups: [ - { - id: applicationSecurityGroup1.id - location: location - properties: {} - } - ] - } - - } - ] - } -} - -resource nic2 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nicName2 - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig2' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip2.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnetName) - } - applicationSecurityGroups: [ - { - id: applicationSecurityGroup2.id - location: location - properties: {} - } - ] - } - } - ] - } -} - -resource vm1 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vmName1 - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vmName1 - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'Standard_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic1.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - storageUri: stg.properties.primaryEndpoints.blob - } - } - } -} - - -resource vm2 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vmName2 - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vmName2 - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'Standard_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic2.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - storageUri: stg.properties.primaryEndpoints.blob - } - } - } -} - - -resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-08-01' = { - name: 'Install-IIS' - location: location - parent: vm1 - properties: { - autoUpgradeMinorVersion: false - enableAutomaticUpgrade: false - publisher: 'Microsoft.compute' - settings: { - fileUris: ['https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/tutorial-vm-extension/installWebServer.ps1'] - commandToExecute: 'powershell.exe -ExecutionPolicy Unrestricted -File installWebServer.ps1' - } - type: 'CustomScriptExtension' - typeHandlerVersion: '1.7' - } -} - -output hostname string = pip1.properties.dnsSettings.fqdn -output hostname2 string = pip2.properties.dnsSettings.fqdn +@description('Username for the Virtual Machine.') +param adminUsername string + +@description('Password for the Virtual Machine.') +@minLength(12) +@secure() +param adminPassword string + +@description('Unique DNS Name for the Public IP used to access the first Virtual Machine.') +param dnsLabelPrefix1 string = toLower('${vmName1}-${uniqueString(resourceGroup().id, vmName1)}') + +@description('Unique DNS Name for the Public IP used to access the second Virtual Machine.') +param dnsLabelPrefix2 string = toLower('${vmName2}-${uniqueString(resourceGroup().id, vmName2)}') + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName1 string = 'myPublicIP1' + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName2 string = 'myPublicIP2' + +@description('Allocation method for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Dynamic' + 'Static' +]) +param publicIPAllocationMethod string = 'Dynamic' + +@description('SKU for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Basic' + 'Standard' +]) +param publicIpSku string = 'Basic' + +@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') +@allowed([ +'2022-datacenter' +'2022-datacenter-azure-edition' +'2022-datacenter-azure-edition-core' +]) +param OSVersion string = '2022-datacenter-azure-edition-core' + +@description('Size of the virtual machine.') +param vmSize string = 'Standard_D2s_v3' + +@description('Location for all resources.') +param location string = resourceGroup().location + +@description('Name of the virtual machine.') +param vmName1 string = 'myVMWeb' + +@description('Name of the virtual machine.') +param vmName2 string = 'myVMMgmt' + +var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' +var nicName1 = 'nic1' +var nicName2 = 'nic2' +var addressPrefix = '10.0.0.0/16' +var subnetName = 'default' +var subnetPrefix = '10.0.0.0/24' +var virtualNetworkName = 'myVirtualNetwork' +var networkSecurityGroupName = 'myNsg' +var applicationSecurityGroupName1 = 'myAsgWebServers' +var applicationSecurityGroupName2 = 'myAsgMgmtServers' + + +resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'Storage' +} + +resource pip1 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName1 + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix1 + } + } +} + +resource pip2 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName2 + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix2 + } + } +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'Allow-RDP-All' + properties: { + priority: 100 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '3389' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + { + name: 'Allow-WEB-HTTP' + properties: { + priority: 200 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '80' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + { + name: 'Allow-WEB-HTTPS' + properties: { + priority: 300 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '443' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + ] + } +} + +resource applicationSecurityGroup1 'Microsoft.Network/applicationSecurityGroups@2022-05-01' = { + name: applicationSecurityGroupName1 + location: location + + properties: {} +} + +resource applicationSecurityGroup2 'Microsoft.Network/applicationSecurityGroups@2022-05-01' = { + name: applicationSecurityGroupName2 + location: location + + properties: {} +} + +resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: subnetPrefix + networkSecurityGroup: { + id: networkSecurityGroup.id + } + } + } + ] + } +} + +resource nic1 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nicName1 + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip1.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnetName) + } + applicationSecurityGroups: [ + { + id: applicationSecurityGroup1.id + location: location + properties: {} + } + ] + } + + } + ] + } +} + +resource nic2 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nicName2 + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig2' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip2.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnetName) + } + applicationSecurityGroups: [ + { + id: applicationSecurityGroup2.id + location: location + properties: {} + } + ] + } + } + ] + } +} + +resource vm1 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vmName1 + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName1 + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'Standard_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic1.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + storageUri: stg.properties.primaryEndpoints.blob + } + } + } +} + + +resource vm2 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vmName2 + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName2 + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'Standard_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic2.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + storageUri: stg.properties.primaryEndpoints.blob + } + } + } +} + + +resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-08-01' = { + name: 'Install-IIS' + location: location + parent: vm1 + properties: { + autoUpgradeMinorVersion: false + enableAutomaticUpgrade: false + publisher: 'Microsoft.compute' + settings: { + fileUris: ['https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/tutorial-vm-extension/installWebServer.ps1'] + commandToExecute: 'powershell.exe -ExecutionPolicy Unrestricted -File installWebServer.ps1' + } + type: 'CustomScriptExtension' + typeHandlerVersion: '1.7' + } +} + +output hostname string = pip1.properties.dnsSettings.fqdn +output hostname2 string = pip2.properties.dnsSettings.fqdn diff --git a/Allfiles/Labs/04/main.bicepparam b/Allfiles/Labs/04/main.bicepparam index c36ceb6..bfca5b0 100644 --- a/Allfiles/Labs/04/main.bicepparam +++ b/Allfiles/Labs/04/main.bicepparam @@ -1,6 +1,6 @@ -using './main.bicep' - -param vmSize = 'Standard_D2s_v3' -param adminUsername = 'Student' -param adminPassword = 'Pa55w.rd1234' - +using './main.bicep' + +param vmSize = 'Standard_D2s_v3' +param adminUsername = 'Student' +param adminPassword = 'Pa55w.rd1234' + diff --git a/Allfiles/Labs/07/main.bicep b/Allfiles/Labs/07/main.bicep index 0fcca33..dab4f94 100644 --- a/Allfiles/Labs/07/main.bicep +++ b/Allfiles/Labs/07/main.bicep @@ -1,364 +1,364 @@ -@description('Username for the Virtual Machine.') -param adminUsername string - -@description('Password for the Virtual Machine.') -@minLength(12) -@secure() -param adminPassword string - -@description('Unique DNS Name for the Public IP used to access the first Virtual Machine.') -param dnsLabelPrefix1 string = toLower('${vmName1}-${uniqueString(resourceGroup().id, vmName1)}') - -@description('Unique DNS Name for the Public IP used to access the second Virtual Machine.') -param dnsLabelPrefix2 string = toLower('${vmName2}-${uniqueString(resourceGroup().id, vmName2)}') - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName1 string = 'myPublicIP1' - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName2 string = 'myPublicIP2' - -@description('Allocation method for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Dynamic' - 'Static' -]) -param publicIPAllocationMethod string = 'Dynamic' - -@description('SKU for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Basic' - 'Standard' -]) -param publicIpSku string = 'Basic' - -@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') -@allowed([ -'2022-datacenter' -'2022-datacenter-azure-edition' -'2022-datacenter-azure-edition-core' -]) -param OSVersion string = '2022-datacenter-azure-edition-core' - -@description('Size of the virtual machine.') -param vmSize string = 'Standard_D2s_v3' - -@description('Location for all resources.') -param location string = resourceGroup().location - -@description('Name of the virtual machine.') -param vmName1 string = 'myVMWeb' - -@description('Name of the virtual machine.') -param vmName2 string = 'myVMMgmt' - -var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' -var nicName1 = 'nic1' -var nicName2 = 'nic2' -var addressPrefix = '10.0.0.0/16' -var subnetName = 'default' -var subnetPrefix = '10.0.0.0/24' -var virtualNetworkName = 'myVirtualNetwork' -var networkSecurityGroupName = 'myNsg' -var applicationSecurityGroupName1 = 'myAsgWebServers' -var applicationSecurityGroupName2 = 'myAsgMgmtServers' - - -resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { - name: storageAccountName - location: location - sku: { - name: 'Standard_LRS' - } - kind: 'Storage' -} - -resource pip1 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName1 - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix1 - } - } -} - -resource pip2 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName2 - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix2 - } - } -} - -resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { - name: networkSecurityGroupName - location: location - properties: { - securityRules: [ - { - name: 'Allow-RDP-All' - properties: { - priority: 100 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '3389' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'Allow-WEB-HTTP' - properties: { - priority: 200 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '80' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'Allow-WEB-HTTPS' - properties: { - priority: 300 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '443' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - ] - } -} - -resource applicationSecurityGroup1 'Microsoft.Network/applicationSecurityGroups@2022-05-01' = { - name: applicationSecurityGroupName1 - location: location - - properties: {} -} - -resource applicationSecurityGroup2 'Microsoft.Network/applicationSecurityGroups@2022-05-01' = { - name: applicationSecurityGroupName2 - location: location - - properties: {} -} - -resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: subnetName - properties: { - addressPrefix: subnetPrefix - networkSecurityGroup: { - id: networkSecurityGroup.id - } - } - } - ] - } -} - -resource nic1 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nicName1 - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip1.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnetName) - } - applicationSecurityGroups: [ - { - id: applicationSecurityGroup1.id - location: location - properties: {} - } - ] - } - - } - ] - } -} - -resource nic2 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nicName2 - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig2' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip2.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnetName) - } - applicationSecurityGroups: [ - { - id: applicationSecurityGroup2.id - location: location - properties: {} - } - ] - } - } - ] - } -} - -resource vm1 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vmName1 - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vmName1 - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'Standard_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic1.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - storageUri: stg.properties.primaryEndpoints.blob - } - } - } -} - - -resource vm2 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vmName2 - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vmName2 - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'Standard_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic2.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - storageUri: stg.properties.primaryEndpoints.blob - } - } - } -} - - -resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-08-01' = { - name: 'Install-IIS' - location: location - parent: vm1 - properties: { - autoUpgradeMinorVersion: false - enableAutomaticUpgrade: false - publisher: 'Microsoft.compute' - settings: { - fileUris: ['https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/tutorial-vm-extension/installWebServer.ps1'] - commandToExecute: 'powershell.exe -ExecutionPolicy Unrestricted -File installWebServer.ps1' - } - type: 'CustomScriptExtension' - typeHandlerVersion: '1.7' - } -} - -output hostname string = pip1.properties.dnsSettings.fqdn -output hostname2 string = pip2.properties.dnsSettings.fqdn +@description('Username for the Virtual Machine.') +param adminUsername string + +@description('Password for the Virtual Machine.') +@minLength(12) +@secure() +param adminPassword string + +@description('Unique DNS Name for the Public IP used to access the first Virtual Machine.') +param dnsLabelPrefix1 string = toLower('${vmName1}-${uniqueString(resourceGroup().id, vmName1)}') + +@description('Unique DNS Name for the Public IP used to access the second Virtual Machine.') +param dnsLabelPrefix2 string = toLower('${vmName2}-${uniqueString(resourceGroup().id, vmName2)}') + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName1 string = 'myPublicIP1' + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName2 string = 'myPublicIP2' + +@description('Allocation method for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Dynamic' + 'Static' +]) +param publicIPAllocationMethod string = 'Dynamic' + +@description('SKU for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Basic' + 'Standard' +]) +param publicIpSku string = 'Basic' + +@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') +@allowed([ +'2022-datacenter' +'2022-datacenter-azure-edition' +'2022-datacenter-azure-edition-core' +]) +param OSVersion string = '2022-datacenter-azure-edition-core' + +@description('Size of the virtual machine.') +param vmSize string = 'Standard_D2s_v3' + +@description('Location for all resources.') +param location string = resourceGroup().location + +@description('Name of the virtual machine.') +param vmName1 string = 'myVMWeb' + +@description('Name of the virtual machine.') +param vmName2 string = 'myVMMgmt' + +var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' +var nicName1 = 'nic1' +var nicName2 = 'nic2' +var addressPrefix = '10.0.0.0/16' +var subnetName = 'default' +var subnetPrefix = '10.0.0.0/24' +var virtualNetworkName = 'myVirtualNetwork' +var networkSecurityGroupName = 'myNsg' +var applicationSecurityGroupName1 = 'myAsgWebServers' +var applicationSecurityGroupName2 = 'myAsgMgmtServers' + + +resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'Storage' +} + +resource pip1 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName1 + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix1 + } + } +} + +resource pip2 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName2 + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix2 + } + } +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'Allow-RDP-All' + properties: { + priority: 100 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '3389' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + { + name: 'Allow-WEB-HTTP' + properties: { + priority: 200 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '80' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + { + name: 'Allow-WEB-HTTPS' + properties: { + priority: 300 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '443' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + ] + } +} + +resource applicationSecurityGroup1 'Microsoft.Network/applicationSecurityGroups@2022-05-01' = { + name: applicationSecurityGroupName1 + location: location + + properties: {} +} + +resource applicationSecurityGroup2 'Microsoft.Network/applicationSecurityGroups@2022-05-01' = { + name: applicationSecurityGroupName2 + location: location + + properties: {} +} + +resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: subnetPrefix + networkSecurityGroup: { + id: networkSecurityGroup.id + } + } + } + ] + } +} + +resource nic1 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nicName1 + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip1.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnetName) + } + applicationSecurityGroups: [ + { + id: applicationSecurityGroup1.id + location: location + properties: {} + } + ] + } + + } + ] + } +} + +resource nic2 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nicName2 + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig2' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip2.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnetName) + } + applicationSecurityGroups: [ + { + id: applicationSecurityGroup2.id + location: location + properties: {} + } + ] + } + } + ] + } +} + +resource vm1 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vmName1 + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName1 + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'Standard_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic1.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + storageUri: stg.properties.primaryEndpoints.blob + } + } + } +} + + +resource vm2 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vmName2 + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName2 + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'Standard_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic2.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + storageUri: stg.properties.primaryEndpoints.blob + } + } + } +} + + +resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-08-01' = { + name: 'Install-IIS' + location: location + parent: vm1 + properties: { + autoUpgradeMinorVersion: false + enableAutomaticUpgrade: false + publisher: 'Microsoft.compute' + settings: { + fileUris: ['https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/tutorial-vm-extension/installWebServer.ps1'] + commandToExecute: 'powershell.exe -ExecutionPolicy Unrestricted -File installWebServer.ps1' + } + type: 'CustomScriptExtension' + typeHandlerVersion: '1.7' + } +} + +output hostname string = pip1.properties.dnsSettings.fqdn +output hostname2 string = pip2.properties.dnsSettings.fqdn diff --git a/Allfiles/Labs/08/main.bicepparam b/Allfiles/Labs/08/main.bicepparam index 16760a3..87fb07a 100644 --- a/Allfiles/Labs/08/main.bicepparam +++ b/Allfiles/Labs/08/main.bicepparam @@ -1,14 +1,14 @@ -using './main.bicep' - -param virtualMachines_Srv_Jump_name = 'Srv-Jump' -param virtualMachines_Srv_Work_name = 'Srv-Work' -param virtualNetworks_Test_FW_VN_name = 'Test-FW-VN' -param networkInterfaces_srv_jump121_name = 'srv-jump121' -param networkInterfaces_srv_work267_name = 'srv-work267' -param publicIPAddresses_Srv_Jump_PIP_name = 'Srv-Jump-PIP' -param networkSecurityGroups_Srv_Jump_nsg_name = 'Srv-Jump-nsg' -param networkSecurityGroups_Srv_Work_nsg_name = 'Srv-Work-nsg' -param schedules_shutdown_computevm_srv_jump_name = 'shutdown-computevm-srv-jump' -param schedules_shutdown_computevm_srv_work_name = 'shutdown-computevm-srv-work' -param location = 'eastus' - +using './main.bicep' + +param virtualMachines_Srv_Jump_name = 'Srv-Jump' +param virtualMachines_Srv_Work_name = 'Srv-Work' +param virtualNetworks_Test_FW_VN_name = 'Test-FW-VN' +param networkInterfaces_srv_jump121_name = 'srv-jump121' +param networkInterfaces_srv_work267_name = 'srv-work267' +param publicIPAddresses_Srv_Jump_PIP_name = 'Srv-Jump-PIP' +param networkSecurityGroups_Srv_Jump_nsg_name = 'Srv-Jump-nsg' +param networkSecurityGroups_Srv_Work_nsg_name = 'Srv-Work-nsg' +param schedules_shutdown_computevm_srv_jump_name = 'shutdown-computevm-srv-jump' +param schedules_shutdown_computevm_srv_work_name = 'shutdown-computevm-srv-work' +param location = 'eastus' + diff --git a/Allfiles/Labs/08/template.json b/Allfiles/Labs/08/template.json index ce92fab..f105446 100644 --- a/Allfiles/Labs/08/template.json +++ b/Allfiles/Labs/08/template.json @@ -2,6 +2,13 @@ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { + "adminUsername": { + "defaultValue": "localadmin", + "type": "string" + }, + "adminPassword": { + "type": "secureString" + }, "virtualMachines_Srv_Jump_name": { "defaultValue": "Srv-Jump", "type": "string" @@ -433,8 +440,8 @@ }, "osProfile": { "computerName": "[parameters('virtualMachines_Srv_Jump_name')]", - "adminUsername": "localadmin", - "adminPassword" : "Pa55w.rd1234", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword" : "[parameters('adminPassword')]", "windowsConfiguration": { "provisionVMAgent": true, "enableAutomaticUpdates": true @@ -485,8 +492,8 @@ }, "osProfile": { "computerName": "[parameters('virtualMachines_Srv_Work_name')]", - "adminUsername": "localadmin", - "adminPassword": "Pa55w.rd1234", + "adminUsername": "[parameters('adminUsername')]", + "adminPassword" : "[parameters('adminPassword')]", "windowsConfiguration": { "provisionVMAgent": true, "enableAutomaticUpdates": true diff --git a/Allfiles/Labs/10/main.bicepparam b/Allfiles/Labs/10/main.bicepparam index d3f0905..77597af 100644 --- a/Allfiles/Labs/10/main.bicepparam +++ b/Allfiles/Labs/10/main.bicepparam @@ -1,8 +1,8 @@ -using './main.bicep' - -param adminUsername = 'Student' - -param adminPassword = 'Pa55w.rd1234' - -param location = 'eastus' - +using './main.bicep' + +param adminUsername = 'Student' + +param adminPassword = 'Pa55w.rd1234' + +param location = 'eastus' + diff --git a/Allfiles/Labs/11/main.bicepparam b/Allfiles/Labs/11/main.bicepparam index 6693f31..1ab3d7d 100644 --- a/Allfiles/Labs/11/main.bicepparam +++ b/Allfiles/Labs/11/main.bicepparam @@ -1,4 +1,4 @@ -using './main.bicep' - -param location = 'eastus' - +using './main.bicep' + +param location = 'eastus' + diff --git a/Allfiles/Labs/12/azuredeploy.parameters.json b/Allfiles/Labs/12/azuredeploy.parameters.json index 89aef6e..6fa69ba 100644 --- a/Allfiles/Labs/12/azuredeploy.parameters.json +++ b/Allfiles/Labs/12/azuredeploy.parameters.json @@ -1,9 +1,9 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "value": "AzurePassw0rd!!" - } - } +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "adminPassword": { + "value": "AzurePassw0rd!!" + } + } } \ No newline at end of file diff --git a/Allfiles/Labs/12/main.bicep b/Allfiles/Labs/12/main.bicep index bdfdb6f..9daaa24 100644 --- a/Allfiles/Labs/12/main.bicep +++ b/Allfiles/Labs/12/main.bicep @@ -1,441 +1,441 @@ -@description('location name') -param location string = 'EastUS' - -@description('VNet name') -param vnetName string = 'myVirtualNetwork' - -@description('Address prefix') -param vnetAddressPrefix string = '10.0.0.0/16' - -@description('Subnet 1 Prefix') -param subnet1Prefix string = '10.0.0.0/24' - -@description('Subnet 1 Name') -param subnet1Name string = 'Public' - -@description('Subnet 2 Prefix') -param subnet2Prefix string = '10.0.1.0/24' - -@description('Subnet 2 Name') -param subnet2Name string = 'Private' - -@description('Network security group name') -param nsgName string = 'myNsgPrivate' - -@description('Array containing security rules. For properties format refer to https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups?tabs=bicep#securityrulepropertiesformat') -param securityRules array = [ - { - name: 'Allow-Storage-All' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '*' - protocol: '*' - sourcePortRange: '*' - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: 'Storage' - } - } - { - name: 'Deny-Internet-All' - properties: { - priority: 1100 - access: 'Deny' - direction: 'Outbound' - destinationPortRange: '*' - protocol: '*' - sourcePortRange: '*' - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: 'Internet' - } - } - { - name: 'Allow-RDP-All' - properties: { - priority: 1200 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '*' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: 'VirtualNetwork' - } - } - -] - -@description('Network security 2 group name') -param nsg2Name string = 'myNsgPublic' - -@description('Specifies the name of the Azure Storage account.') -param storageAccountName string = 'storage${uniqueString(resourceGroup().id)}' - -@description('Specifies the name of the File Share. File share names must be between 3 and 63 characters in length and use numbers, lower-case letters and dash (-) only.') -@minLength(3) -@maxLength(63) -param fileShareName string = 'my-file-share' - -@description('Username for the Virtual Machine.') -param adminUsername string = 'localadmin' - -@description('Password for the Virtual Machine.') -@minLength(12) -@secure() -param adminPassword string - -@description('Name of virtual machine 1.') -param vmName string = 'myVmPrivate' - -@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') -param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id, vmName)}') - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName string = 'myVmPrivate-ip' - -@description('Allocation method for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Dynamic' - 'Static' -]) -param publicIPAllocationMethod string = 'Dynamic' - -@description('SKU for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Basic' - 'Standard' -]) -param publicIpSku string = 'Basic' - -@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') -@allowed([ -'2022-datacenter-g2' -]) -param OSVersion string = '2022-datacenter-g2' - -@description('Size of the virtual machine.') -param vmSize string = 'Standard_D2s_v5' - -var nicName = 'myVM1Nic' - -//Parameters for VM2 -@description('Name of virtual machine 1.') -param vm2Name string = 'myVmPublic' - -@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') -param dnsLabelPrefix2 string = toLower('${vm2Name}-${uniqueString(resourceGroup().id, vm2Name)}') - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName2 string = 'myVmPublic-ip' - -var nic2Name = 'myVM2Nic' - -//Task 1 and 2: Create Vnet with two subnets, and configure a storage endpoint -resource vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { - name: vnetName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - vnetAddressPrefix - ] - } - subnets: [ - { - name: subnet1Name - properties: { - networkSecurityGroup: { - id: nsg2.id - } - addressPrefix: subnet1Prefix - } - } - { - name: subnet2Name - properties: { - addressPrefix: subnet2Prefix - networkSecurityGroup: { - id: nsg.id - } - serviceEndpoints: [ - { - service: 'Microsoft.Storage' - locations: [ - 'eastus' - 'westus' - 'westus3' - ] - } - ] - delegations: [] - privateEndpointNetworkPolicies: 'Disabled' - privateLinkServiceNetworkPolicies: 'Enabled' - } - type: 'Microsoft.Network/virtualNetworks/subnets' - } - ] - } -} - -//Task 3: Configure a network security group to restrict access to the subnet -resource nsg 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { - name: nsgName - location: location - properties: { - securityRules: [for rule in securityRules: { - name: rule.name - properties: rule.properties - }] - } -} - -//Task 4: Configure a network security group to allow rdp on the public subnet -resource nsg2 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { - name: nsg2Name - location: location - properties: { - securityRules: [ - { - name: 'Allow-RDP-All' - properties: { - priority: 1200 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '3389' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: 'VirtualNetwork' - } - }] - } -} - -// Task 5: Create a storage account with a file share -resource sa 'Microsoft.Storage/storageAccounts@2022-09-01' = { - name: storageAccountName - location: location - kind: 'StorageV2' - sku: { - name: 'Standard_LRS' - } - properties: { - dnsEndpointType: 'Standard' - defaultToOAuthAuthentication: false - publicNetworkAccess: 'Enabled' - allowCrossTenantReplication: true - minimumTlsVersion: 'TLS1_2' - allowBlobPublicAccess: true - allowSharedKeyAccess: true - networkAcls: { - bypass: 'AzureServices' - virtualNetworkRules: [ - { - id: '${vnet.id}/subnets/Private' - action: 'Allow' - state: 'Succeeded' - } - ] - ipRules: [] - defaultAction: 'Deny' - } - supportsHttpsTrafficOnly: true - encryption: { - requireInfrastructureEncryption: false - services: { - file: { - keyType: 'Account' - enabled: true - } - blob: { - keyType: 'Account' - enabled: true - } - } - keySource: 'Microsoft.Storage' - } - accessTier: 'Hot' - } -} - -resource fileShare 'Microsoft.Storage/storageAccounts/fileServices/shares@2021-04-01' = { - name: '${sa.name}/default/${fileShareName}' -} - - -// At this point in the lab you have configured a virtual network, a network security group, and a storage account with a file share. - -// Task 6: Deploy virtual machines into the designated subnets - -//Create VM1 -resource pip 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix - } - } -} - - -resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nicName - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnet2Name) - } - } - } - ] - } -} - -resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vmName - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vmName - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'StandardSSD_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic.id - } - ] - } - } -} - - -//Create VM2 - -resource pip2 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName2 - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix2 - } - } -} - - -resource nic2 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nic2Name - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip2.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnet1Name) - } - } - } - ] - } -} - -resource vm2 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vm2Name - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vm2Name - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'StandardSSD_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic2.id - } - ] - } - } -} - -output hostname string = pip.properties.dnsSettings.fqdn -output hostname2 string = pip2.properties.dnsSettings.fqdn - -//Once the deployment completes, -//On the my-file-share blade, click Connect. -//On the Connect blade, on the Windows tab, copy the PowerShell script that creates a Z drive mapping to the file share. - -//Then execute Task 7 from the VM. -//Task 7: Test the storage connection from the private subnet to confirm that access is allowed +@description('location name') +param location string = 'EastUS' + +@description('VNet name') +param vnetName string = 'myVirtualNetwork' + +@description('Address prefix') +param vnetAddressPrefix string = '10.0.0.0/16' + +@description('Subnet 1 Prefix') +param subnet1Prefix string = '10.0.0.0/24' + +@description('Subnet 1 Name') +param subnet1Name string = 'Public' + +@description('Subnet 2 Prefix') +param subnet2Prefix string = '10.0.1.0/24' + +@description('Subnet 2 Name') +param subnet2Name string = 'Private' + +@description('Network security group name') +param nsgName string = 'myNsgPrivate' + +@description('Array containing security rules. For properties format refer to https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups?tabs=bicep#securityrulepropertiesformat') +param securityRules array = [ + { + name: 'Allow-Storage-All' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '*' + protocol: '*' + sourcePortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'Storage' + } + } + { + name: 'Deny-Internet-All' + properties: { + priority: 1100 + access: 'Deny' + direction: 'Outbound' + destinationPortRange: '*' + protocol: '*' + sourcePortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'Internet' + } + } + { + name: 'Allow-RDP-All' + properties: { + priority: 1200 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '*' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: 'VirtualNetwork' + } + } + +] + +@description('Network security 2 group name') +param nsg2Name string = 'myNsgPublic' + +@description('Specifies the name of the Azure Storage account.') +param storageAccountName string = 'storage${uniqueString(resourceGroup().id)}' + +@description('Specifies the name of the File Share. File share names must be between 3 and 63 characters in length and use numbers, lower-case letters and dash (-) only.') +@minLength(3) +@maxLength(63) +param fileShareName string = 'my-file-share' + +@description('Username for the Virtual Machine.') +param adminUsername string = 'localadmin' + +@description('Password for the Virtual Machine.') +@minLength(12) +@secure() +param adminPassword string + +@description('Name of virtual machine 1.') +param vmName string = 'myVmPrivate' + +@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') +param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id, vmName)}') + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName string = 'myVmPrivate-ip' + +@description('Allocation method for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Dynamic' + 'Static' +]) +param publicIPAllocationMethod string = 'Dynamic' + +@description('SKU for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Basic' + 'Standard' +]) +param publicIpSku string = 'Basic' + +@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') +@allowed([ +'2022-datacenter-g2' +]) +param OSVersion string = '2022-datacenter-g2' + +@description('Size of the virtual machine.') +param vmSize string = 'Standard_D2s_v5' + +var nicName = 'myVM1Nic' + +//Parameters for VM2 +@description('Name of virtual machine 1.') +param vm2Name string = 'myVmPublic' + +@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') +param dnsLabelPrefix2 string = toLower('${vm2Name}-${uniqueString(resourceGroup().id, vm2Name)}') + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName2 string = 'myVmPublic-ip' + +var nic2Name = 'myVM2Nic' + +//Task 1 and 2: Create Vnet with two subnets, and configure a storage endpoint +resource vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: vnetName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + vnetAddressPrefix + ] + } + subnets: [ + { + name: subnet1Name + properties: { + networkSecurityGroup: { + id: nsg2.id + } + addressPrefix: subnet1Prefix + } + } + { + name: subnet2Name + properties: { + addressPrefix: subnet2Prefix + networkSecurityGroup: { + id: nsg.id + } + serviceEndpoints: [ + { + service: 'Microsoft.Storage' + locations: [ + 'eastus' + 'westus' + 'westus3' + ] + } + ] + delegations: [] + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + type: 'Microsoft.Network/virtualNetworks/subnets' + } + ] + } +} + +//Task 3: Configure a network security group to restrict access to the subnet +resource nsg 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { + name: nsgName + location: location + properties: { + securityRules: [for rule in securityRules: { + name: rule.name + properties: rule.properties + }] + } +} + +//Task 4: Configure a network security group to allow rdp on the public subnet +resource nsg2 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { + name: nsg2Name + location: location + properties: { + securityRules: [ + { + name: 'Allow-RDP-All' + properties: { + priority: 1200 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '3389' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: 'VirtualNetwork' + } + }] + } +} + +// Task 5: Create a storage account with a file share +resource sa 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: storageAccountName + location: location + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + properties: { + dnsEndpointType: 'Standard' + defaultToOAuthAuthentication: false + publicNetworkAccess: 'Enabled' + allowCrossTenantReplication: true + minimumTlsVersion: 'TLS1_2' + allowBlobPublicAccess: true + allowSharedKeyAccess: true + networkAcls: { + bypass: 'AzureServices' + virtualNetworkRules: [ + { + id: '${vnet.id}/subnets/Private' + action: 'Allow' + state: 'Succeeded' + } + ] + ipRules: [] + defaultAction: 'Deny' + } + supportsHttpsTrafficOnly: true + encryption: { + requireInfrastructureEncryption: false + services: { + file: { + keyType: 'Account' + enabled: true + } + blob: { + keyType: 'Account' + enabled: true + } + } + keySource: 'Microsoft.Storage' + } + accessTier: 'Hot' + } +} + +resource fileShare 'Microsoft.Storage/storageAccounts/fileServices/shares@2021-04-01' = { + name: '${sa.name}/default/${fileShareName}' +} + + +// At this point in the lab you have configured a virtual network, a network security group, and a storage account with a file share. + +// Task 6: Deploy virtual machines into the designated subnets + +//Create VM1 +resource pip 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix + } + } +} + + +resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nicName + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnet2Name) + } + } + } + ] + } +} + +resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vmName + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'StandardSSD_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic.id + } + ] + } + } +} + + +//Create VM2 + +resource pip2 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName2 + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix2 + } + } +} + + +resource nic2 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nic2Name + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip2.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnet1Name) + } + } + } + ] + } +} + +resource vm2 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vm2Name + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vm2Name + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'StandardSSD_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic2.id + } + ] + } + } +} + +output hostname string = pip.properties.dnsSettings.fqdn +output hostname2 string = pip2.properties.dnsSettings.fqdn + +//Once the deployment completes, +//On the my-file-share blade, click Connect. +//On the Connect blade, on the Windows tab, copy the PowerShell script that creates a Z drive mapping to the file share. + +//Then execute Task 7 from the VM. +//Task 7: Test the storage connection from the private subnet to confirm that access is allowed diff --git a/Allfiles/Labs/12/main.bicepparam b/Allfiles/Labs/12/main.bicepparam index 5626208..47da7d4 100644 --- a/Allfiles/Labs/12/main.bicepparam +++ b/Allfiles/Labs/12/main.bicepparam @@ -1,64 +1,64 @@ -using './main.bicep' - -param location = 'EastUS' -param vnetName = 'myVirtualNetwork' -param vnetAddressPrefix = '10.0.0.0/16' -param subnet1Prefix = '10.0.0.0/24' -param subnet1Name = 'Public' -param subnet2Prefix = '10.0.1.0/24' -param subnet2Name = 'Private' -param nsgName = 'myNsgPrivate' -param securityRules = [ - { - name: 'Allow-Storage-All' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '*' - protocol: '*' - sourcePortRange: '*' - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: 'Storage' - } - } - { - name: 'Deny-Internet-All' - properties: { - priority: 1100 - access: 'Deny' - direction: 'Outbound' - destinationPortRange: '*' - protocol: '*' - sourcePortRange: '*' - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: 'Internet' - } - } - { - name: 'Allow-RDP-All' - properties: { - priority: 1200 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '*' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: 'VirtualNetwork' - } - } -] -param nsg2Name = 'myNsgPublic' -param fileShareName = 'my-file-share' -param adminUsername = 'localadmin' -param adminPassword = '' -param vmName = 'myVmPrivate' -param publicIpName = 'myVmPrivate-ip' -param publicIPAllocationMethod = 'Dynamic' -param publicIpSku = 'Basic' -param OSVersion = '2022-datacenter-g2' -param vmSize = 'Standard_D2s_v5' -param vm2Name = 'myVmPublic' -param publicIpName2 = 'myVmPublic-ip' - +using './main.bicep' + +param location = 'EastUS' +param vnetName = 'myVirtualNetwork' +param vnetAddressPrefix = '10.0.0.0/16' +param subnet1Prefix = '10.0.0.0/24' +param subnet1Name = 'Public' +param subnet2Prefix = '10.0.1.0/24' +param subnet2Name = 'Private' +param nsgName = 'myNsgPrivate' +param securityRules = [ + { + name: 'Allow-Storage-All' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '*' + protocol: '*' + sourcePortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'Storage' + } + } + { + name: 'Deny-Internet-All' + properties: { + priority: 1100 + access: 'Deny' + direction: 'Outbound' + destinationPortRange: '*' + protocol: '*' + sourcePortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'Internet' + } + } + { + name: 'Allow-RDP-All' + properties: { + priority: 1200 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '*' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: 'VirtualNetwork' + } + } +] +param nsg2Name = 'myNsgPublic' +param fileShareName = 'my-file-share' +param adminUsername = 'localadmin' +param adminPassword = '' +param vmName = 'myVmPrivate' +param publicIpName = 'myVmPrivate-ip' +param publicIPAllocationMethod = 'Dynamic' +param publicIpSku = 'Basic' +param OSVersion = '2022-datacenter-g2' +param vmSize = 'Standard_D2s_v5' +param vm2Name = 'myVmPublic' +param publicIpName2 = 'myVmPublic-ip' + diff --git a/Allfiles/Labs/13/azuredeploy.parameters.json b/Allfiles/Labs/13/azuredeploy.parameters.json index c800fad..efc6b43 100644 --- a/Allfiles/Labs/13/azuredeploy.parameters.json +++ b/Allfiles/Labs/13/azuredeploy.parameters.json @@ -1,9 +1,9 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "value": "AzureTest01!!" - } - } +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "adminPassword": { + "value": "AzureTest01!!" + } + } } \ No newline at end of file diff --git a/Allfiles/Labs/13/main.bicep b/Allfiles/Labs/13/main.bicep index 954c63f..fc2f2d4 100644 --- a/Allfiles/Labs/13/main.bicep +++ b/Allfiles/Labs/13/main.bicep @@ -1,245 +1,245 @@ -@description('Username for the Virtual Machine.') -param adminUsername string = 'localadmin' - -@description('Password for the Virtual Machine.') -@minLength(12) -@secure() -param adminPassword string - -@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') -param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id, vmName)}') - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName string = 'myPublicIpAddress' - -@description('Allocation method for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Dynamic' - 'Static' -]) -param publicIPAllocationMethod string = 'Static' - -@description('SKU for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Basic' - 'Standard' -]) -param publicIpSku string = 'Standard' - -@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') -@allowed([ -'2016-Datacenter' -'2022-datacenter' -'2022-datacenter-azure-edition-core' -]) -param OSVersion string = '2022-datacenter-azure-edition-core' - -@description('Size of the virtual machine.') -param vmSize string = 'Standard_D2s_v5' - -@description('Location for all resources.') -param location string = 'eastus' - -@description('Name of the virtual machine.') -param vmName string = 'myVM' - -param logAnalyticsWorkspaceName string = 'la-${uniqueString(resourceGroup().id)}' - - -var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' -var nicName = 'myVMNic' -var addressPrefix = '192.168.0.0/16' -var subnetName = 'mySubnet' -var subnetPrefix = '192.168.1.0/24' -var virtualNetworkName = 'myVnet' -var networkSecurityGroupName = 'myNetworkSecurityGroup' -var primaryKey = logAnalyticsWorkspace.listKeys().primarySharedKey - -//Task 1: Deploy an Azure virtual machine with a public IP address and a network security group -resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { - name: storageAccountName - location: location - sku: { - name: 'Standard_LRS' - } - kind: 'Storage' -} - -resource pip 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix - } - } -} - -resource securityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { - name: networkSecurityGroupName - location: location - properties: { - securityRules: [ - { - name: 'allow-3389' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '3389' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'allow-http' - properties: { - priority: 1100 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '80' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - ] - } -} - -resource vn 'Microsoft.Network/virtualNetworks@2021-02-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: subnetName - properties: { - addressPrefix: subnetPrefix - networkSecurityGroup: { - id: securityGroup.id - } - } - } - ] - } -} - -resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nicName - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vn.name, subnetName) - } - } - } - ] - } -} - -resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vmName - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vmName - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'StandardSSD_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - storageUri: stg.properties.primaryEndpoints.blob - } - } - } -} - -//Task 2: Create a Log Analytics workspace -resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { - name: logAnalyticsWorkspaceName - location: location - properties: any({ - retentionInDays: 30 - features: { - searchVersion: 1 - } - sku: { - name: 'PerGB2018' - } - }) -} - -//Task 3: Enable the Log Analytics virtual machine extension -resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { - parent: vm - name: 'Microsoft.Insights.LogAnalyticsAgent' - location: location - properties: { - publisher: 'Microsoft.Azure.Monitor' - type: 'AzureMonitorWindowsAgent' - autoUpgradeMinorVersion: true - typeHandlerVersion: '1.14' - settings: { - workspaceId: logAnalyticsWorkspace.id - } - protectedSettings: { - workspaceKey: primaryKey - } - } -} - - -output hostname string = pip.properties.dnsSettings.fqdn +@description('Username for the Virtual Machine.') +param adminUsername string = 'localadmin' + +@description('Password for the Virtual Machine.') +@minLength(12) +@secure() +param adminPassword string + +@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') +param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id, vmName)}') + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName string = 'myPublicIpAddress' + +@description('Allocation method for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Dynamic' + 'Static' +]) +param publicIPAllocationMethod string = 'Static' + +@description('SKU for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Basic' + 'Standard' +]) +param publicIpSku string = 'Standard' + +@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') +@allowed([ +'2016-Datacenter' +'2022-datacenter' +'2022-datacenter-azure-edition-core' +]) +param OSVersion string = '2022-datacenter-azure-edition-core' + +@description('Size of the virtual machine.') +param vmSize string = 'Standard_D2s_v5' + +@description('Location for all resources.') +param location string = 'eastus' + +@description('Name of the virtual machine.') +param vmName string = 'myVM' + +param logAnalyticsWorkspaceName string = 'la-${uniqueString(resourceGroup().id)}' + + +var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' +var nicName = 'myVMNic' +var addressPrefix = '192.168.0.0/16' +var subnetName = 'mySubnet' +var subnetPrefix = '192.168.1.0/24' +var virtualNetworkName = 'myVnet' +var networkSecurityGroupName = 'myNetworkSecurityGroup' +var primaryKey = logAnalyticsWorkspace.listKeys().primarySharedKey + +//Task 1: Deploy an Azure virtual machine with a public IP address and a network security group +resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'Storage' +} + +resource pip 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix + } + } +} + +resource securityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'allow-3389' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '3389' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + { + name: 'allow-http' + properties: { + priority: 1100 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '80' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + ] + } +} + +resource vn 'Microsoft.Network/virtualNetworks@2021-02-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: subnetPrefix + networkSecurityGroup: { + id: securityGroup.id + } + } + } + ] + } +} + +resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nicName + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vn.name, subnetName) + } + } + } + ] + } +} + +resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vmName + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'StandardSSD_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + storageUri: stg.properties.primaryEndpoints.blob + } + } + } +} + +//Task 2: Create a Log Analytics workspace +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: logAnalyticsWorkspaceName + location: location + properties: any({ + retentionInDays: 30 + features: { + searchVersion: 1 + } + sku: { + name: 'PerGB2018' + } + }) +} + +//Task 3: Enable the Log Analytics virtual machine extension +resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { + parent: vm + name: 'Microsoft.Insights.LogAnalyticsAgent' + location: location + properties: { + publisher: 'Microsoft.Azure.Monitor' + type: 'AzureMonitorWindowsAgent' + autoUpgradeMinorVersion: true + typeHandlerVersion: '1.14' + settings: { + workspaceId: logAnalyticsWorkspace.id + } + protectedSettings: { + workspaceKey: primaryKey + } + } +} + + +output hostname string = pip.properties.dnsSettings.fqdn diff --git a/Allfiles/Labs/13/main.bicepparam b/Allfiles/Labs/13/main.bicepparam index 1535c5c..c38e6df 100644 --- a/Allfiles/Labs/13/main.bicepparam +++ b/Allfiles/Labs/13/main.bicepparam @@ -1,12 +1,12 @@ -using './main.bicep' - -param adminUsername = 'localadmin' -param adminPassword = 'AzureTest01!!' -param publicIpName = 'myPublicIpAddress' -param publicIPAllocationMethod = 'Static' -param publicIpSku = 'Standard' -param OSVersion = '2022-datacenter-azure-edition-core' -param vmSize = 'Standard_D2s_v5' -param location = 'eastus' -param vmName = 'myVM' - +using './main.bicep' + +param adminUsername = 'localadmin' +param adminPassword = 'AzureTest01!!' +param publicIpName = 'myPublicIpAddress' +param publicIPAllocationMethod = 'Static' +param publicIpSku = 'Standard' +param OSVersion = '2022-datacenter-azure-edition-core' +param vmSize = 'Standard_D2s_v5' +param location = 'eastus' +param vmName = 'myVM' + diff --git a/Allfiles/Labs/14/azuredeploy.parameters.json b/Allfiles/Labs/14/azuredeploy.parameters.json index c800fad..efc6b43 100644 --- a/Allfiles/Labs/14/azuredeploy.parameters.json +++ b/Allfiles/Labs/14/azuredeploy.parameters.json @@ -1,9 +1,9 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "value": "AzureTest01!!" - } - } +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "adminPassword": { + "value": "AzureTest01!!" + } + } } \ No newline at end of file diff --git a/Allfiles/Labs/14/defender-for-cloud.bicep b/Allfiles/Labs/14/defender-for-cloud.bicep index 8a48d36..8dfbbf7 100644 --- a/Allfiles/Labs/14/defender-for-cloud.bicep +++ b/Allfiles/Labs/14/defender-for-cloud.bicep @@ -1,237 +1,237 @@ -targetScope = 'subscription' - -@description('Required. The full Azure ID of the workspace to save the data in.') -param workspaceId string - -@description('Required. All the VMs in this scope will send their security data to the mentioned workspace unless overridden by a setting with more specific scope.') -param scope string - -@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') -param enableDefaultTelemetry bool = true - -@description('Optional. Describes what kind of security agent provisioning action to take. - On or Off.') -@allowed([ - 'On' - 'Off' -]) -param autoProvision string = 'On' - -@description('Optional. Device Security group data.') -param deviceSecurityGroupProperties object = {} - -@description('Optional. The pricing tier value for VMs. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param virtualMachinesPricingTier string = 'Free' - -@description('Optional. The pricing tier value for SqlServers. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param sqlServersPricingTier string = 'Free' - -@description('Optional. The pricing tier value for AppServices. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param appServicesPricingTier string = 'Free' - -@description('Optional. The pricing tier value for StorageAccounts. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param storageAccountsPricingTier string = 'Free' - -@description('Optional. The pricing tier value for SqlServerVirtualMachines. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param sqlServerVirtualMachinesPricingTier string = 'Free' - -@description('Optional. The pricing tier value for KubernetesService. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param kubernetesServicePricingTier string = 'Free' - -@description('Optional. The pricing tier value for ContainerRegistry. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param containerRegistryPricingTier string = 'Free' - -@description('Optional. The pricing tier value for KeyVaults. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param keyVaultsPricingTier string = 'Free' - -@description('Optional. The pricing tier value for DNS. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param dnsPricingTier string = 'Free' - -@description('Optional. The pricing tier value for ARM. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param armPricingTier string = 'Free' - -@description('Optional. The pricing tier value for OpenSourceRelationalDatabases. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param openSourceRelationalDatabasesTier string = 'Free' - -@description('Optional. The pricing tier value for containers. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param containersTier string = 'Free' - -@description('Optional. The pricing tier value for CosmosDbs. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param cosmosDbsTier string = 'Free' - -@description('Optional. Security contact data.') -param securityContactProperties object = {} - -@description('Optional. Location deployment metadata.') -param location string = deployment().location - -var pricings = [ - { - name: 'VirtualMachines' - pricingTier: virtualMachinesPricingTier - } - { - name: 'SqlServers' - pricingTier: sqlServersPricingTier - } - { - name: 'AppServices' - pricingTier: appServicesPricingTier - } - { - name: 'StorageAccounts' - pricingTier: storageAccountsPricingTier - } - { - name: 'SqlServerVirtualMachines' - pricingTier: sqlServerVirtualMachinesPricingTier - } - { - name: 'KubernetesService' - pricingTier: kubernetesServicePricingTier - } - { - name: 'ContainerRegistry' - pricingTier: containerRegistryPricingTier - } - { - name: 'KeyVaults' - pricingTier: keyVaultsPricingTier - } - { - name: 'Dns' - pricingTier: dnsPricingTier - } - { - name: 'Arm' - pricingTier: armPricingTier - } - { - name: 'OpenSourceRelationalDatabases' - pricingTier: openSourceRelationalDatabasesTier - } - { - name: 'Containers' - pricingTier: containersTier - } - { - name: 'CosmosDbs' - pricingTier: cosmosDbsTier - } -] - -resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { - name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' - location: location - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - } - } -} - -resource pricingTiers 'Microsoft.Security/pricings@2018-06-01' = [for (pricing, index) in pricings: { - name: pricing.name - properties: { - pricingTier: pricing.pricingTier - } -}] - -resource autoProvisioningSettings 'Microsoft.Security/autoProvisioningSettings@2017-08-01-preview' = { - name: 'default' - properties: { - autoProvision: autoProvision - } -} - -resource deviceSecurityGroups 'Microsoft.Security/deviceSecurityGroups@2019-08-01' = if (!empty(deviceSecurityGroupProperties)) { - name: 'deviceSecurityGroups' - properties: { - thresholdRules: deviceSecurityGroupProperties.thresholdRules - timeWindowRules: deviceSecurityGroupProperties.timeWindowRules - allowlistRules: deviceSecurityGroupProperties.allowlistRules - denylistRules: deviceSecurityGroupProperties.denylistRules - } -} - - -resource securityContacts 'Microsoft.Security/securityContacts@2017-08-01-preview' = if (!empty(securityContactProperties)) { - name: 'default' - properties: { - email: securityContactProperties.email - phone: securityContactProperties.phone - alertNotifications: securityContactProperties.alertNotifications - alertsToAdmins: securityContactProperties.alertsToAdmins - } -} - -resource workspaceSettings 'Microsoft.Security/workspaceSettings@2017-08-01-preview' = { - name: 'default' - properties: { - workspaceId: workspaceId - scope: scope - } - dependsOn: [ - autoProvisioningSettings - ] -} - -@description('The resource ID of the used log analytics workspace.') -output workspaceId string = workspaceId - -@description('The name of the security center.') -output name string = 'Security' +targetScope = 'subscription' + +@description('Required. The full Azure ID of the workspace to save the data in.') +param workspaceId string + +@description('Required. All the VMs in this scope will send their security data to the mentioned workspace unless overridden by a setting with more specific scope.') +param scope string + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +@description('Optional. Describes what kind of security agent provisioning action to take. - On or Off.') +@allowed([ + 'On' + 'Off' +]) +param autoProvision string = 'On' + +@description('Optional. Device Security group data.') +param deviceSecurityGroupProperties object = {} + +@description('Optional. The pricing tier value for VMs. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param virtualMachinesPricingTier string = 'Free' + +@description('Optional. The pricing tier value for SqlServers. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param sqlServersPricingTier string = 'Free' + +@description('Optional. The pricing tier value for AppServices. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param appServicesPricingTier string = 'Free' + +@description('Optional. The pricing tier value for StorageAccounts. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param storageAccountsPricingTier string = 'Free' + +@description('Optional. The pricing tier value for SqlServerVirtualMachines. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param sqlServerVirtualMachinesPricingTier string = 'Free' + +@description('Optional. The pricing tier value for KubernetesService. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param kubernetesServicePricingTier string = 'Free' + +@description('Optional. The pricing tier value for ContainerRegistry. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param containerRegistryPricingTier string = 'Free' + +@description('Optional. The pricing tier value for KeyVaults. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param keyVaultsPricingTier string = 'Free' + +@description('Optional. The pricing tier value for DNS. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param dnsPricingTier string = 'Free' + +@description('Optional. The pricing tier value for ARM. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param armPricingTier string = 'Free' + +@description('Optional. The pricing tier value for OpenSourceRelationalDatabases. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param openSourceRelationalDatabasesTier string = 'Free' + +@description('Optional. The pricing tier value for containers. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param containersTier string = 'Free' + +@description('Optional. The pricing tier value for CosmosDbs. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param cosmosDbsTier string = 'Free' + +@description('Optional. Security contact data.') +param securityContactProperties object = {} + +@description('Optional. Location deployment metadata.') +param location string = deployment().location + +var pricings = [ + { + name: 'VirtualMachines' + pricingTier: virtualMachinesPricingTier + } + { + name: 'SqlServers' + pricingTier: sqlServersPricingTier + } + { + name: 'AppServices' + pricingTier: appServicesPricingTier + } + { + name: 'StorageAccounts' + pricingTier: storageAccountsPricingTier + } + { + name: 'SqlServerVirtualMachines' + pricingTier: sqlServerVirtualMachinesPricingTier + } + { + name: 'KubernetesService' + pricingTier: kubernetesServicePricingTier + } + { + name: 'ContainerRegistry' + pricingTier: containerRegistryPricingTier + } + { + name: 'KeyVaults' + pricingTier: keyVaultsPricingTier + } + { + name: 'Dns' + pricingTier: dnsPricingTier + } + { + name: 'Arm' + pricingTier: armPricingTier + } + { + name: 'OpenSourceRelationalDatabases' + pricingTier: openSourceRelationalDatabasesTier + } + { + name: 'Containers' + pricingTier: containersTier + } + { + name: 'CosmosDbs' + pricingTier: cosmosDbsTier + } +] + +resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { + name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' + location: location + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} + +resource pricingTiers 'Microsoft.Security/pricings@2018-06-01' = [for (pricing, index) in pricings: { + name: pricing.name + properties: { + pricingTier: pricing.pricingTier + } +}] + +resource autoProvisioningSettings 'Microsoft.Security/autoProvisioningSettings@2017-08-01-preview' = { + name: 'default' + properties: { + autoProvision: autoProvision + } +} + +resource deviceSecurityGroups 'Microsoft.Security/deviceSecurityGroups@2019-08-01' = if (!empty(deviceSecurityGroupProperties)) { + name: 'deviceSecurityGroups' + properties: { + thresholdRules: deviceSecurityGroupProperties.thresholdRules + timeWindowRules: deviceSecurityGroupProperties.timeWindowRules + allowlistRules: deviceSecurityGroupProperties.allowlistRules + denylistRules: deviceSecurityGroupProperties.denylistRules + } +} + + +resource securityContacts 'Microsoft.Security/securityContacts@2017-08-01-preview' = if (!empty(securityContactProperties)) { + name: 'default' + properties: { + email: securityContactProperties.email + phone: securityContactProperties.phone + alertNotifications: securityContactProperties.alertNotifications + alertsToAdmins: securityContactProperties.alertsToAdmins + } +} + +resource workspaceSettings 'Microsoft.Security/workspaceSettings@2017-08-01-preview' = { + name: 'default' + properties: { + workspaceId: workspaceId + scope: scope + } + dependsOn: [ + autoProvisioningSettings + ] +} + +@description('The resource ID of the used log analytics workspace.') +output workspaceId string = workspaceId + +@description('The name of the security center.') +output name string = 'Security' diff --git a/Allfiles/Labs/14/main.bicep b/Allfiles/Labs/14/main.bicep index 1de3ef1..391711f 100644 --- a/Allfiles/Labs/14/main.bicep +++ b/Allfiles/Labs/14/main.bicep @@ -1,271 +1,271 @@ -param rgName string = 'AZ500LAB131415' - -param defenderAutoProvision string = 'On' -param defenderAppServicesPricingTier string = 'Standard' -param defenderVirtualMachinesPricingTier string = 'Standard' -param defenderSqlServersPricingTier string = 'Standard' -param defenderStorageAccountsPricingTier string = 'Standard' -param defenderDnsPricingTier string ='Standard' -param defenderArmPricingTier string = 'Standard' - -@description('Username for the Virtual Machine.') -param adminUsername string = 'localadmin' - -@description('Password for the Virtual Machine.') -@minLength(12) -@secure() -param adminPassword string - -@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') -param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id, vmName)}') - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName string = 'myPublicIpAddress' - -@description('Allocation method for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Dynamic' - 'Static' -]) -param publicIPAllocationMethod string = 'Static' - -@description('SKU for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Basic' - 'Standard' -]) -param publicIpSku string = 'Standard' - -@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') -@allowed([ -'2016-Datacenter' -'2022-datacenter' -'2022-datacenter-azure-edition-core' -]) -param OSVersion string = '2022-datacenter-azure-edition-core' - -@description('Size of the virtual machine.') -param vmSize string = 'Standard_D2s_v5' - -@description('Location for all resources.') -param location string = 'eastus' - -@description('Name of the virtual machine.') -param vmName string = 'myVM' - -param logAnalyticsWorkspaceName string = 'la-${uniqueString(resourceGroup().id)}' - - -var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' -var nicName = 'myVMNic' -var addressPrefix = '192.168.0.0/16' -var subnetName = 'mySubnet' -var subnetPrefix = '192.168.1.0/24' -var virtualNetworkName = 'myVnet' -var networkSecurityGroupName = 'myNetworkSecurityGroup' -var primaryKey = logAnalyticsWorkspace.listKeys().primarySharedKey - -// Deploy an Azure virtual machine with a public IP address and a network security group -resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { - name: storageAccountName - location: location - sku: { - name: 'Standard_LRS' - } - kind: 'Storage' -} - -resource pip 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix - } - } -} - -resource securityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { - name: networkSecurityGroupName - location: location - properties: { - securityRules: [ - { - name: 'allow-3389' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '3389' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'allow-http' - properties: { - priority: 1100 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '80' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - ] - } -} - -resource vn 'Microsoft.Network/virtualNetworks@2021-02-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: subnetName - properties: { - addressPrefix: subnetPrefix - networkSecurityGroup: { - id: securityGroup.id - } - } - } - ] - } -} - -resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nicName - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vn.name, subnetName) - } - } - } - ] - } -} - -resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vmName - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vmName - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'StandardSSD_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - storageUri: stg.properties.primaryEndpoints.blob - } - } - } -} - -// Create a Log Analytics workspace -resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { - name: logAnalyticsWorkspaceName - location: location - properties: any({ - retentionInDays: 30 - features: { - searchVersion: 1 - } - sku: { - name: 'PerGB2018' - } - }) -} - -// Enable the Log Analytics virtual machine extension -resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { - parent: vm - name: 'Microsoft.Insights.LogAnalyticsAgent' - location: location - properties: { - publisher: 'Microsoft.Azure.Monitor' - type: 'AzureMonitorWindowsAgent' - autoUpgradeMinorVersion: true - typeHandlerVersion: '1.14' - settings: { - workspaceId: logAnalyticsWorkspace.id - } - protectedSettings: { - workspaceKey: primaryKey - } - } -} - -//Enable Defender for Cloud -module defenderForCloud 'defender-for-cloud.bicep' = { - scope: subscription() - name: 'defenderForCloud' - params: { - scope: subscription().id - workspaceId: logAnalyticsWorkspace.id - autoProvision: defenderAutoProvision - virtualMachinesPricingTier: defenderVirtualMachinesPricingTier - sqlServersPricingTier: defenderSqlServersPricingTier - storageAccountsPricingTier: defenderStorageAccountsPricingTier - appServicesPricingTier: defenderAppServicesPricingTier - dnsPricingTier: defenderDnsPricingTier - armPricingTier: defenderArmPricingTier - } -} - -output hostname string = pip.properties.dnsSettings.fqdn +param rgName string = 'AZ500LAB131415' + +param defenderAutoProvision string = 'On' +param defenderAppServicesPricingTier string = 'Standard' +param defenderVirtualMachinesPricingTier string = 'Standard' +param defenderSqlServersPricingTier string = 'Standard' +param defenderStorageAccountsPricingTier string = 'Standard' +param defenderDnsPricingTier string ='Standard' +param defenderArmPricingTier string = 'Standard' + +@description('Username for the Virtual Machine.') +param adminUsername string = 'localadmin' + +@description('Password for the Virtual Machine.') +@minLength(12) +@secure() +param adminPassword string + +@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') +param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id, vmName)}') + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName string = 'myPublicIpAddress' + +@description('Allocation method for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Dynamic' + 'Static' +]) +param publicIPAllocationMethod string = 'Static' + +@description('SKU for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Basic' + 'Standard' +]) +param publicIpSku string = 'Standard' + +@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') +@allowed([ +'2016-Datacenter' +'2022-datacenter' +'2022-datacenter-azure-edition-core' +]) +param OSVersion string = '2022-datacenter-azure-edition-core' + +@description('Size of the virtual machine.') +param vmSize string = 'Standard_D2s_v5' + +@description('Location for all resources.') +param location string = 'eastus' + +@description('Name of the virtual machine.') +param vmName string = 'myVM' + +param logAnalyticsWorkspaceName string = 'la-${uniqueString(resourceGroup().id)}' + + +var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' +var nicName = 'myVMNic' +var addressPrefix = '192.168.0.0/16' +var subnetName = 'mySubnet' +var subnetPrefix = '192.168.1.0/24' +var virtualNetworkName = 'myVnet' +var networkSecurityGroupName = 'myNetworkSecurityGroup' +var primaryKey = logAnalyticsWorkspace.listKeys().primarySharedKey + +// Deploy an Azure virtual machine with a public IP address and a network security group +resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'Storage' +} + +resource pip 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix + } + } +} + +resource securityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'allow-3389' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '3389' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + { + name: 'allow-http' + properties: { + priority: 1100 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '80' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + ] + } +} + +resource vn 'Microsoft.Network/virtualNetworks@2021-02-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: subnetPrefix + networkSecurityGroup: { + id: securityGroup.id + } + } + } + ] + } +} + +resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nicName + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vn.name, subnetName) + } + } + } + ] + } +} + +resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vmName + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'StandardSSD_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + storageUri: stg.properties.primaryEndpoints.blob + } + } + } +} + +// Create a Log Analytics workspace +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: logAnalyticsWorkspaceName + location: location + properties: any({ + retentionInDays: 30 + features: { + searchVersion: 1 + } + sku: { + name: 'PerGB2018' + } + }) +} + +// Enable the Log Analytics virtual machine extension +resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { + parent: vm + name: 'Microsoft.Insights.LogAnalyticsAgent' + location: location + properties: { + publisher: 'Microsoft.Azure.Monitor' + type: 'AzureMonitorWindowsAgent' + autoUpgradeMinorVersion: true + typeHandlerVersion: '1.14' + settings: { + workspaceId: logAnalyticsWorkspace.id + } + protectedSettings: { + workspaceKey: primaryKey + } + } +} + +//Enable Defender for Cloud +module defenderForCloud 'defender-for-cloud.bicep' = { + scope: subscription() + name: 'defenderForCloud' + params: { + scope: subscription().id + workspaceId: logAnalyticsWorkspace.id + autoProvision: defenderAutoProvision + virtualMachinesPricingTier: defenderVirtualMachinesPricingTier + sqlServersPricingTier: defenderSqlServersPricingTier + storageAccountsPricingTier: defenderStorageAccountsPricingTier + appServicesPricingTier: defenderAppServicesPricingTier + dnsPricingTier: defenderDnsPricingTier + armPricingTier: defenderArmPricingTier + } +} + +output hostname string = pip.properties.dnsSettings.fqdn diff --git a/Allfiles/Labs/14/main.bicepparam b/Allfiles/Labs/14/main.bicepparam index 9a9e1f0..94d7da3 100644 --- a/Allfiles/Labs/14/main.bicepparam +++ b/Allfiles/Labs/14/main.bicepparam @@ -1,19 +1,19 @@ -using './main.bicep' - -param rgName = 'AZ500LAB131415' -param defenderAutoProvision = 'On' -param defenderAppServicesPricingTier = 'Standard' -param defenderVirtualMachinesPricingTier = 'Standard' -param defenderSqlServersPricingTier = 'Standard' -param defenderStorageAccountsPricingTier = 'Standard' -param defenderDnsPricingTier = 'Standard' -param defenderArmPricingTier = 'Standard' -param adminUsername = 'localadmin' -param adminPassword = 'AzureTest01!!' -param publicIpName = 'myPublicIpAddress' -param publicIPAllocationMethod = 'Static' -param publicIpSku = 'Standard' -param OSVersion = '2022-datacenter-azure-edition-core' -param vmSize = 'Standard_D2s_v5' -param location = 'eastus' -param vmName = 'myVM' +using './main.bicep' + +param rgName = 'AZ500LAB131415' +param defenderAutoProvision = 'On' +param defenderAppServicesPricingTier = 'Standard' +param defenderVirtualMachinesPricingTier = 'Standard' +param defenderSqlServersPricingTier = 'Standard' +param defenderStorageAccountsPricingTier = 'Standard' +param defenderDnsPricingTier = 'Standard' +param defenderArmPricingTier = 'Standard' +param adminUsername = 'localadmin' +param adminPassword = 'AzureTest01!!' +param publicIpName = 'myPublicIpAddress' +param publicIPAllocationMethod = 'Static' +param publicIpSku = 'Standard' +param OSVersion = '2022-datacenter-azure-edition-core' +param vmSize = 'Standard_D2s_v5' +param location = 'eastus' +param vmName = 'myVM' diff --git a/Allfiles/Labs/15/azuredeploy.parameters.json b/Allfiles/Labs/15/azuredeploy.parameters.json index c800fad..efc6b43 100644 --- a/Allfiles/Labs/15/azuredeploy.parameters.json +++ b/Allfiles/Labs/15/azuredeploy.parameters.json @@ -1,9 +1,9 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "adminPassword": { - "value": "AzureTest01!!" - } - } +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "adminPassword": { + "value": "AzureTest01!!" + } + } } \ No newline at end of file diff --git a/Allfiles/Labs/15/defender-for-cloud.bicep b/Allfiles/Labs/15/defender-for-cloud.bicep index 8a48d36..8dfbbf7 100644 --- a/Allfiles/Labs/15/defender-for-cloud.bicep +++ b/Allfiles/Labs/15/defender-for-cloud.bicep @@ -1,237 +1,237 @@ -targetScope = 'subscription' - -@description('Required. The full Azure ID of the workspace to save the data in.') -param workspaceId string - -@description('Required. All the VMs in this scope will send their security data to the mentioned workspace unless overridden by a setting with more specific scope.') -param scope string - -@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') -param enableDefaultTelemetry bool = true - -@description('Optional. Describes what kind of security agent provisioning action to take. - On or Off.') -@allowed([ - 'On' - 'Off' -]) -param autoProvision string = 'On' - -@description('Optional. Device Security group data.') -param deviceSecurityGroupProperties object = {} - -@description('Optional. The pricing tier value for VMs. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param virtualMachinesPricingTier string = 'Free' - -@description('Optional. The pricing tier value for SqlServers. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param sqlServersPricingTier string = 'Free' - -@description('Optional. The pricing tier value for AppServices. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param appServicesPricingTier string = 'Free' - -@description('Optional. The pricing tier value for StorageAccounts. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param storageAccountsPricingTier string = 'Free' - -@description('Optional. The pricing tier value for SqlServerVirtualMachines. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param sqlServerVirtualMachinesPricingTier string = 'Free' - -@description('Optional. The pricing tier value for KubernetesService. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param kubernetesServicePricingTier string = 'Free' - -@description('Optional. The pricing tier value for ContainerRegistry. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param containerRegistryPricingTier string = 'Free' - -@description('Optional. The pricing tier value for KeyVaults. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param keyVaultsPricingTier string = 'Free' - -@description('Optional. The pricing tier value for DNS. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param dnsPricingTier string = 'Free' - -@description('Optional. The pricing tier value for ARM. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param armPricingTier string = 'Free' - -@description('Optional. The pricing tier value for OpenSourceRelationalDatabases. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param openSourceRelationalDatabasesTier string = 'Free' - -@description('Optional. The pricing tier value for containers. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param containersTier string = 'Free' - -@description('Optional. The pricing tier value for CosmosDbs. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') -@allowed([ - 'Free' - 'Standard' -]) -param cosmosDbsTier string = 'Free' - -@description('Optional. Security contact data.') -param securityContactProperties object = {} - -@description('Optional. Location deployment metadata.') -param location string = deployment().location - -var pricings = [ - { - name: 'VirtualMachines' - pricingTier: virtualMachinesPricingTier - } - { - name: 'SqlServers' - pricingTier: sqlServersPricingTier - } - { - name: 'AppServices' - pricingTier: appServicesPricingTier - } - { - name: 'StorageAccounts' - pricingTier: storageAccountsPricingTier - } - { - name: 'SqlServerVirtualMachines' - pricingTier: sqlServerVirtualMachinesPricingTier - } - { - name: 'KubernetesService' - pricingTier: kubernetesServicePricingTier - } - { - name: 'ContainerRegistry' - pricingTier: containerRegistryPricingTier - } - { - name: 'KeyVaults' - pricingTier: keyVaultsPricingTier - } - { - name: 'Dns' - pricingTier: dnsPricingTier - } - { - name: 'Arm' - pricingTier: armPricingTier - } - { - name: 'OpenSourceRelationalDatabases' - pricingTier: openSourceRelationalDatabasesTier - } - { - name: 'Containers' - pricingTier: containersTier - } - { - name: 'CosmosDbs' - pricingTier: cosmosDbsTier - } -] - -resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { - name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' - location: location - properties: { - mode: 'Incremental' - template: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: '1.0.0.0' - resources: [] - } - } -} - -resource pricingTiers 'Microsoft.Security/pricings@2018-06-01' = [for (pricing, index) in pricings: { - name: pricing.name - properties: { - pricingTier: pricing.pricingTier - } -}] - -resource autoProvisioningSettings 'Microsoft.Security/autoProvisioningSettings@2017-08-01-preview' = { - name: 'default' - properties: { - autoProvision: autoProvision - } -} - -resource deviceSecurityGroups 'Microsoft.Security/deviceSecurityGroups@2019-08-01' = if (!empty(deviceSecurityGroupProperties)) { - name: 'deviceSecurityGroups' - properties: { - thresholdRules: deviceSecurityGroupProperties.thresholdRules - timeWindowRules: deviceSecurityGroupProperties.timeWindowRules - allowlistRules: deviceSecurityGroupProperties.allowlistRules - denylistRules: deviceSecurityGroupProperties.denylistRules - } -} - - -resource securityContacts 'Microsoft.Security/securityContacts@2017-08-01-preview' = if (!empty(securityContactProperties)) { - name: 'default' - properties: { - email: securityContactProperties.email - phone: securityContactProperties.phone - alertNotifications: securityContactProperties.alertNotifications - alertsToAdmins: securityContactProperties.alertsToAdmins - } -} - -resource workspaceSettings 'Microsoft.Security/workspaceSettings@2017-08-01-preview' = { - name: 'default' - properties: { - workspaceId: workspaceId - scope: scope - } - dependsOn: [ - autoProvisioningSettings - ] -} - -@description('The resource ID of the used log analytics workspace.') -output workspaceId string = workspaceId - -@description('The name of the security center.') -output name string = 'Security' +targetScope = 'subscription' + +@description('Required. The full Azure ID of the workspace to save the data in.') +param workspaceId string + +@description('Required. All the VMs in this scope will send their security data to the mentioned workspace unless overridden by a setting with more specific scope.') +param scope string + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableDefaultTelemetry bool = true + +@description('Optional. Describes what kind of security agent provisioning action to take. - On or Off.') +@allowed([ + 'On' + 'Off' +]) +param autoProvision string = 'On' + +@description('Optional. Device Security group data.') +param deviceSecurityGroupProperties object = {} + +@description('Optional. The pricing tier value for VMs. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param virtualMachinesPricingTier string = 'Free' + +@description('Optional. The pricing tier value for SqlServers. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param sqlServersPricingTier string = 'Free' + +@description('Optional. The pricing tier value for AppServices. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param appServicesPricingTier string = 'Free' + +@description('Optional. The pricing tier value for StorageAccounts. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param storageAccountsPricingTier string = 'Free' + +@description('Optional. The pricing tier value for SqlServerVirtualMachines. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param sqlServerVirtualMachinesPricingTier string = 'Free' + +@description('Optional. The pricing tier value for KubernetesService. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param kubernetesServicePricingTier string = 'Free' + +@description('Optional. The pricing tier value for ContainerRegistry. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param containerRegistryPricingTier string = 'Free' + +@description('Optional. The pricing tier value for KeyVaults. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param keyVaultsPricingTier string = 'Free' + +@description('Optional. The pricing tier value for DNS. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param dnsPricingTier string = 'Free' + +@description('Optional. The pricing tier value for ARM. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param armPricingTier string = 'Free' + +@description('Optional. The pricing tier value for OpenSourceRelationalDatabases. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param openSourceRelationalDatabasesTier string = 'Free' + +@description('Optional. The pricing tier value for containers. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param containersTier string = 'Free' + +@description('Optional. The pricing tier value for CosmosDbs. Azure Security Center is provided in two pricing tiers: free and standard, with the standard tier available with a trial period. The standard tier offers advanced security capabilities, while the free tier offers basic security features. - Free or Standard.') +@allowed([ + 'Free' + 'Standard' +]) +param cosmosDbsTier string = 'Free' + +@description('Optional. Security contact data.') +param securityContactProperties object = {} + +@description('Optional. Location deployment metadata.') +param location string = deployment().location + +var pricings = [ + { + name: 'VirtualMachines' + pricingTier: virtualMachinesPricingTier + } + { + name: 'SqlServers' + pricingTier: sqlServersPricingTier + } + { + name: 'AppServices' + pricingTier: appServicesPricingTier + } + { + name: 'StorageAccounts' + pricingTier: storageAccountsPricingTier + } + { + name: 'SqlServerVirtualMachines' + pricingTier: sqlServerVirtualMachinesPricingTier + } + { + name: 'KubernetesService' + pricingTier: kubernetesServicePricingTier + } + { + name: 'ContainerRegistry' + pricingTier: containerRegistryPricingTier + } + { + name: 'KeyVaults' + pricingTier: keyVaultsPricingTier + } + { + name: 'Dns' + pricingTier: dnsPricingTier + } + { + name: 'Arm' + pricingTier: armPricingTier + } + { + name: 'OpenSourceRelationalDatabases' + pricingTier: openSourceRelationalDatabasesTier + } + { + name: 'Containers' + pricingTier: containersTier + } + { + name: 'CosmosDbs' + pricingTier: cosmosDbsTier + } +] + +resource defaultTelemetry 'Microsoft.Resources/deployments@2021-04-01' = if (enableDefaultTelemetry) { + name: 'pid-47ed15a6-730a-4827-bcb4-0fd963ffbd82-${uniqueString(deployment().name, location)}' + location: location + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} + +resource pricingTiers 'Microsoft.Security/pricings@2018-06-01' = [for (pricing, index) in pricings: { + name: pricing.name + properties: { + pricingTier: pricing.pricingTier + } +}] + +resource autoProvisioningSettings 'Microsoft.Security/autoProvisioningSettings@2017-08-01-preview' = { + name: 'default' + properties: { + autoProvision: autoProvision + } +} + +resource deviceSecurityGroups 'Microsoft.Security/deviceSecurityGroups@2019-08-01' = if (!empty(deviceSecurityGroupProperties)) { + name: 'deviceSecurityGroups' + properties: { + thresholdRules: deviceSecurityGroupProperties.thresholdRules + timeWindowRules: deviceSecurityGroupProperties.timeWindowRules + allowlistRules: deviceSecurityGroupProperties.allowlistRules + denylistRules: deviceSecurityGroupProperties.denylistRules + } +} + + +resource securityContacts 'Microsoft.Security/securityContacts@2017-08-01-preview' = if (!empty(securityContactProperties)) { + name: 'default' + properties: { + email: securityContactProperties.email + phone: securityContactProperties.phone + alertNotifications: securityContactProperties.alertNotifications + alertsToAdmins: securityContactProperties.alertsToAdmins + } +} + +resource workspaceSettings 'Microsoft.Security/workspaceSettings@2017-08-01-preview' = { + name: 'default' + properties: { + workspaceId: workspaceId + scope: scope + } + dependsOn: [ + autoProvisioningSettings + ] +} + +@description('The resource ID of the used log analytics workspace.') +output workspaceId string = workspaceId + +@description('The name of the security center.') +output name string = 'Security' diff --git a/Allfiles/Labs/15/main.bicep b/Allfiles/Labs/15/main.bicep index ffcef0c..fffc7d8 100644 --- a/Allfiles/Labs/15/main.bicep +++ b/Allfiles/Labs/15/main.bicep @@ -1,3682 +1,3682 @@ -//On the Logic Apps Designer blade, click the first Connections step. -//ensure that the entry in the Tenant drop down list contains your Azure AD tenant name and Sign-in. - -param rgName string = 'AZ500LAB131415' - -param defenderAutoProvision string = 'On' -param defenderAppServicesPricingTier string = 'Standard' -param defenderVirtualMachinesPricingTier string = 'Standard' -param defenderSqlServersPricingTier string = 'Standard' -param defenderStorageAccountsPricingTier string = 'Standard' -param defenderDnsPricingTier string ='Standard' -param defenderArmPricingTier string = 'Standard' -param PlaybookName string = 'Change-Incident-Severity' - -//Replace the value -param UserName string = '@' - -@description('Username for the Virtual Machine.') -param adminUsername string = 'localadmin' - -@description('Password for the Virtual Machine.') -@minLength(12) -@secure() -param adminPassword string - -@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') -param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id, vmName)}') - -@description('Name for the Public IP used to access the Virtual Machine.') -param publicIpName string = 'myPublicIpAddress' - -@description('Allocation method for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Dynamic' - 'Static' -]) -param publicIPAllocationMethod string = 'Static' - -@description('SKU for the Public IP used to access the Virtual Machine.') -@allowed([ - 'Basic' - 'Standard' -]) -param publicIpSku string = 'Standard' - -@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') -@allowed([ -'2016-Datacenter' -'2022-datacenter' -'2022-datacenter-azure-edition-core' -]) -param OSVersion string = '2022-datacenter-azure-edition-core' - -@description('Size of the virtual machine.') -param vmSize string = 'Standard_D2s_v5' - -@description('Location for all resources.') -param location string = 'eastus' - -@description('Name of the virtual machine.') -param vmName string = 'myVM' - -param logAnalyticsWorkspaceName string = 'la-${uniqueString(resourceGroup().id)}' - -@description('Region to deploy solution resources -- separate from location selection}') -param workspace_location string = 'eastus' - -@description('Workspace name for Log Analytics where Microsoft Sentinel is setup') -param workspace string = logAnalyticsWorkspaceName - -@description('Name for the workbook') -@minLength(1) -param workbook1_name string = 'Azure Activity' - -var AzureSentinelConnectionName = 'azuresentinel-${PlaybookName}' -var solutionName = 'SecurityInsights(${logAnalyticsWorkspace.name})' -var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' -var nicName = 'myVMNic' -var addressPrefix = '192.168.0.0/16' -var subnetName = 'mySubnet' -var subnetPrefix = '192.168.1.0/24' -var virtualNetworkName = 'myVnet' -var networkSecurityGroupName = 'myNetworkSecurityGroup' -var primaryKey = logAnalyticsWorkspace.listKeys().primarySharedKey - - - -var solutionId = 'azuresentinel.azure-sentinel-solution-azureactivity' -var _solutionId = solutionId -var email = 'support@microsoft.com' -var _email = email -var workspaceResourceId = resourceId('microsoft.OperationalInsights/Workspaces', workspace) -var uiConfigId1 = 'AzureActivity' -var _uiConfigId1 = uiConfigId1 -var dataConnectorContentId1 = 'AzureActivity' -var _dataConnectorContentId1 = dataConnectorContentId1 -var dataConnectorId1 = extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', workspace), 'Microsoft.SecurityInsights/dataConnectors', _dataConnectorContentId1) -var _dataConnectorId1 = dataConnectorId1 -var dataConnectorTemplateSpecName1 = '${workspace}-dc-${uniqueString(_dataConnectorContentId1)}' -var dataConnectorVersion1 = '2.0.0' -var huntingQueryVersion1 = '2.0.1' -var huntingQuerycontentId1 = 'ef7ef44e-6129-4d8e-94fe-b5530415d8e5' -var _huntingQuerycontentId1 = huntingQuerycontentId1 -var huntingQueryId1 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId1) -var huntingQueryTemplateSpecName1 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId1)}' -var huntingQueryVersion2 = '2.0.0' -var huntingQuerycontentId2 = '43cb0347-bdcc-4e83-af5a-cebbd03971d8' -var _huntingQuerycontentId2 = huntingQuerycontentId2 -var huntingQueryId2 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId2) -var huntingQueryTemplateSpecName2 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId2)}' -var huntingQueryVersion3 = '2.0.1' -var huntingQuerycontentId3 = '5d2399f9-ea5c-4e67-9435-1fba745f3a39' -var _huntingQuerycontentId3 = huntingQuerycontentId3 -var huntingQueryId3 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId3) -var huntingQueryTemplateSpecName3 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId3)}' -var huntingQueryVersion4 = '2.0.1' -var huntingQuerycontentId4 = '1b8779c9-abf2-444f-a21f-437b8f90ac4a' -var _huntingQuerycontentId4 = huntingQuerycontentId4 -var huntingQueryId4 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId4) -var huntingQueryTemplateSpecName4 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId4)}' -var huntingQueryVersion5 = '2.0.1' -var huntingQuerycontentId5 = 'e94d6756-981c-4f02-9a81-d006d80c8b41' -var _huntingQuerycontentId5 = huntingQuerycontentId5 -var huntingQueryId5 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId5) -var huntingQueryTemplateSpecName5 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId5)}' -var huntingQueryVersion6 = '2.1.1' -var huntingQuerycontentId6 = 'efe843ca-3ce7-4896-9f8b-f2c374ae6527' -var _huntingQuerycontentId6 = huntingQuerycontentId6 -var huntingQueryId6 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId6) -var huntingQueryTemplateSpecName6 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId6)}' -var huntingQueryVersion7 = '2.0.1' -var huntingQuerycontentId7 = '17201aa8-0916-4078-a020-7ea3a9262889' -var _huntingQuerycontentId7 = huntingQuerycontentId7 -var huntingQueryId7 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId7) -var huntingQueryTemplateSpecName7 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId7)}' -var huntingQueryVersion8 = '2.0.1' -var huntingQuerycontentId8 = '5a1f9655-c893-4091-8dc0-7f11d7676506' -var _huntingQuerycontentId8 = huntingQuerycontentId8 -var huntingQueryId8 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId8) -var huntingQueryTemplateSpecName8 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId8)}' -var huntingQueryVersion9 = '2.0.1' -var huntingQuerycontentId9 = '57784ba5-7791-422e-916f-65ef94fe1dbb' -var _huntingQuerycontentId9 = huntingQuerycontentId9 -var huntingQueryId9 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId9) -var huntingQueryTemplateSpecName9 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId9)}' -var huntingQueryVersion10 = '2.0.1' -var huntingQuerycontentId10 = '0278e3b8-9899-45c5-8928-700cd80d2d80' -var _huntingQuerycontentId10 = huntingQuerycontentId10 -var huntingQueryId10 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId10) -var huntingQueryTemplateSpecName10 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId10)}' -var huntingQueryVersion11 = '2.0.1' -var huntingQuerycontentId11 = 'a09e6368-065b-4f1e-a4ce-b1b3a64b493b' -var _huntingQuerycontentId11 = huntingQuerycontentId11 -var huntingQueryId11 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId11) -var huntingQueryTemplateSpecName11 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId11)}' -var huntingQueryVersion12 = '2.0.1' -var huntingQuerycontentId12 = '860cda84-765b-4273-af44-958b7cca85f7' -var _huntingQuerycontentId12 = huntingQuerycontentId12 -var huntingQueryId12 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId12) -var huntingQueryTemplateSpecName12 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId12)}' -var huntingQueryVersion13 = '2.0.1' -var huntingQuerycontentId13 = '9e146876-e303-49af-b847-b029d1a66852' -var _huntingQuerycontentId13 = huntingQuerycontentId13 -var huntingQueryId13 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId13) -var huntingQueryTemplateSpecName13 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId13)}' -var huntingQueryVersion14 = '2.0.1' -var huntingQuerycontentId14 = '81fd68a2-9ad6-4a1c-7bd7-18efe5c99081' -var _huntingQuerycontentId14 = huntingQuerycontentId14 -var huntingQueryId14 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId14) -var huntingQueryTemplateSpecName14 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId14)}' -var analyticRuleVersion1 = '2.0.1' -var analyticRulecontentId1 = '88f453ff-7b9e-45bb-8c12-4058ca5e44ee' -var _analyticRulecontentId1 = analyticRulecontentId1 -var analyticRuleId1 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId1) -var analyticRuleTemplateSpecName1 = '${workspace}-ar-${uniqueString(_analyticRulecontentId1)}' -var analyticRuleVersion2 = '2.0.1' -var analyticRulecontentId2 = '86a036b2-3686-42eb-b417-909fc0867771' -var _analyticRulecontentId2 = analyticRulecontentId2 -var analyticRuleId2 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId2) -var analyticRuleTemplateSpecName2 = '${workspace}-ar-${uniqueString(_analyticRulecontentId2)}' -var analyticRuleVersion3 = '2.0.1' -var analyticRulecontentId3 = 'd9938c3b-16f9-444d-bc22-ea9a9110e0fd' -var _analyticRulecontentId3 = analyticRulecontentId3 -var analyticRuleId3 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId3) -var analyticRuleTemplateSpecName3 = '${workspace}-ar-${uniqueString(_analyticRulecontentId3)}' -var analyticRuleVersion4 = '2.0.3' -var analyticRulecontentId4 = '361dd1e3-1c11-491e-82a3-bb2e44ac36ba' -var _analyticRulecontentId4 = analyticRulecontentId4 -var analyticRuleId4 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId4) -var analyticRuleTemplateSpecName4 = '${workspace}-ar-${uniqueString(_analyticRulecontentId4)}' -var analyticRuleVersion5 = '2.0.1' -var analyticRulecontentId5 = '9736e5f1-7b6e-4bfb-a708-e53ff1d182c3' -var _analyticRulecontentId5 = analyticRulecontentId5 -var analyticRuleId5 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId5) -var analyticRuleTemplateSpecName5 = '${workspace}-ar-${uniqueString(_analyticRulecontentId5)}' -var analyticRuleVersion6 = '2.0.1' -var analyticRulecontentId6 = 'b2c15736-b9eb-4dae-8b02-3016b6a45a32' -var _analyticRulecontentId6 = analyticRulecontentId6 -var analyticRuleId6 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId6) -var analyticRuleTemplateSpecName6 = '${workspace}-ar-${uniqueString(_analyticRulecontentId6)}' -var analyticRuleVersion7 = '2.0.1' -var analyticRulecontentId7 = 'ec491363-5fe7-4eff-b68e-f42dcb76fcf6' -var _analyticRulecontentId7 = analyticRulecontentId7 -var analyticRuleId7 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId7) -var analyticRuleTemplateSpecName7 = '${workspace}-ar-${uniqueString(_analyticRulecontentId7)}' -var analyticRuleVersion8 = '2.0.1' -var analyticRulecontentId8 = '56fe0db0-6779-46fa-b3c5-006082a53064' -var _analyticRulecontentId8 = analyticRulecontentId8 -var analyticRuleId8 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId8) -var analyticRuleTemplateSpecName8 = '${workspace}-ar-${uniqueString(_analyticRulecontentId8)}' -var analyticRuleVersion9 = '2.0.2' -var analyticRulecontentId9 = '6d7214d9-4a28-44df-aafb-0910b9e6ae3e' -var _analyticRulecontentId9 = analyticRulecontentId9 -var analyticRuleId9 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId9) -var analyticRuleTemplateSpecName9 = '${workspace}-ar-${uniqueString(_analyticRulecontentId9)}' -var analyticRuleVersion10 = '2.0.2' -var analyticRulecontentId10 = '9fb57e58-3ed8-4b89-afcf-c8e786508b1c' -var _analyticRulecontentId10 = analyticRulecontentId10 -var analyticRuleId10 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId10) -var analyticRuleTemplateSpecName10 = '${workspace}-ar-${uniqueString(_analyticRulecontentId10)}' -var analyticRuleVersion11 = '2.0.2' -var analyticRulecontentId11 = '23de46ea-c425-4a77-b456-511ae4855d69' -var _analyticRulecontentId11 = analyticRulecontentId11 -var analyticRuleId11 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId11) -var analyticRuleTemplateSpecName11 = '${workspace}-ar-${uniqueString(_analyticRulecontentId11)}' -var analyticRuleVersion12 = '2.0.2' -var analyticRulecontentId12 = 'ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b' -var _analyticRulecontentId12 = analyticRulecontentId12 -var analyticRuleId12 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId12) -var analyticRuleTemplateSpecName12 = '${workspace}-ar-${uniqueString(_analyticRulecontentId12)}' -var TemplateEmptyArray = json('[]') -var blanks = replace('b', 'b', '') -var workbookVersion1 = '2.0.0' -var workbookContentId1 = 'AzureActivityWorkbook' -var workbookId1 = resourceId('Microsoft.Insights/workbooks', workbookContentId1) -var workbookTemplateSpecName1 = '${workspace}-wb-${uniqueString(_workbookContentId1)}' -var _workbookContentId1 = workbookContentId1 - -// Deploy an Azure virtual machine with a public IP address and a network security group -resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { - name: storageAccountName - location: location - sku: { - name: 'Standard_LRS' - } - kind: 'Storage' -} - -resource pip 'Microsoft.Network/publicIPAddresses@2021-02-01' = { - name: publicIpName - location: location - sku: { - name: publicIpSku - } - properties: { - publicIPAllocationMethod: publicIPAllocationMethod - dnsSettings: { - domainNameLabel: dnsLabelPrefix - } - } -} - -resource securityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { - name: networkSecurityGroupName - location: location - properties: { - securityRules: [ - { - name: 'allow-3389' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '3389' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - { - name: 'allow-http' - properties: { - priority: 1100 - access: 'Allow' - direction: 'Inbound' - destinationPortRange: '80' - protocol: 'Tcp' - sourcePortRange: '*' - sourceAddressPrefix: '*' - destinationAddressPrefix: '*' - } - } - ] - } -} - -resource vn 'Microsoft.Network/virtualNetworks@2021-02-01' = { - name: virtualNetworkName - location: location - properties: { - addressSpace: { - addressPrefixes: [ - addressPrefix - ] - } - subnets: [ - { - name: subnetName - properties: { - addressPrefix: subnetPrefix - networkSecurityGroup: { - id: securityGroup.id - } - } - } - ] - } -} - -resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = { - name: nicName - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - privateIPAllocationMethod: 'Dynamic' - publicIPAddress: { - id: pip.id - } - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', vn.name, subnetName) - } - } - } - ] - } -} - -resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' = { - name: vmName - location: location - properties: { - hardwareProfile: { - vmSize: vmSize - } - osProfile: { - computerName: vmName - adminUsername: adminUsername - adminPassword: adminPassword - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: OSVersion - version: 'latest' - } - osDisk: { - createOption: 'FromImage' - managedDisk: { - storageAccountType: 'StandardSSD_LRS' - } - } - dataDisks: [ - { - diskSizeGB: 1023 - lun: 0 - createOption: 'Empty' - } - ] - } - networkProfile: { - networkInterfaces: [ - { - id: nic.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - storageUri: stg.properties.primaryEndpoints.blob - } - } - } -} - -// Create a Log Analytics workspace -resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { - name: logAnalyticsWorkspaceName - location: location - properties: any({ - retentionInDays: 30 - features: { - searchVersion: 1 - } - sku: { - name: 'PerGB2018' - } - }) -} - -// Enable the Log Analytics virtual machine extension -resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { - parent: vm - name: 'Microsoft.Insights.LogAnalyticsAgent' - location: location - properties: { - publisher: 'Microsoft.Azure.Monitor' - type: 'AzureMonitorWindowsAgent' - autoUpgradeMinorVersion: true - typeHandlerVersion: '1.14' - settings: { - workspaceId: logAnalyticsWorkspace.id - } - protectedSettings: { - workspaceKey: primaryKey - } - } -} - -//Enable Sentinel -resource sentinel 'Microsoft.OperationsManagement/solutions@2015-11-01-preview' = { - name: solutionName - location: location - properties: { - workspaceResourceId: logAnalyticsWorkspace.id - } - plan: { - name: solutionName - publisher: 'Microsoft' - product: 'OMSGallery/SecurityInsights' - promotionCode: '' - } -} - -//Enable Defender for Cloud -module defenderForCloud 'defender-for-cloud.bicep' = { - scope: subscription() - name: 'defenderForCloud' - params: { - scope: subscription().id - workspaceId: logAnalyticsWorkspace.id - autoProvision: defenderAutoProvision - virtualMachinesPricingTier: defenderVirtualMachinesPricingTier - sqlServersPricingTier: defenderSqlServersPricingTier - storageAccountsPricingTier: defenderStorageAccountsPricingTier - appServicesPricingTier: defenderAppServicesPricingTier - dnsPricingTier: defenderDnsPricingTier - armPricingTier: defenderArmPricingTier - } -} - - -//Create Playbook and Sentinel connection -resource AzureSentinelConnection 'Microsoft.Web/connections@2016-06-01' = { - name: AzureSentinelConnectionName - location: location - properties: { - displayName: UserName - customParameterValues: {} - api: { - id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${resourceGroup().location}/managedApis/azuresentinel' - } - } -} - -resource Playbook 'Microsoft.Logic/workflows@2019-05-01' = { - name: PlaybookName - location: location - tags: { - LogicAppsCategory: 'security' - } - properties: { - state: 'Enabled' - definition: { - '$schema': 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#' - contentVersion: '1.0.0.0' - parameters: { - '$connections': { - defaultValue: {} - type: 'Object' - } - } - triggers: { - When_a_response_to_an_Azure_Sentinel_alert_is_triggered: { - type: 'ApiConnectionWebhook' - inputs: { - body: { - callback_url: '@{listCallbackUrl()}' - } - host: { - connection: { - name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']' - } - } - path: '/subscribe' - } - } - } - actions: { - 'Alert_-_Get_accounts': { - runAfter: { - 'Alert_-_Get_incident': [ - 'Succeeded' - ] - } - type: 'ApiConnection' - inputs: { - body: '@triggerBody()?[\'Entities\']' - host: { - connection: { - name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']' - } - } - method: 'post' - path: '/entities/account' - } - } - 'Alert_-_Get_incident': { - runAfter: {} - type: 'ApiConnection' - inputs: { - host: { - connection: { - name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']' - } - } - method: 'get' - path: '/Cases/@{encodeURIComponent(triggerBody()?[\'SystemAlertId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceSubscriptionId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceResourceGroup\'])}' - } - } - Change_incident_severity_2: { - runAfter: { - 'Alert_-_Get_accounts': [ - 'Succeeded' - ] - } - type: 'ApiConnection' - inputs: { - host: { - connection: { - name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']' - } - } - method: 'put' - path: '/Case/@{encodeURIComponent(triggerBody()?[\'WorkspaceSubscriptionId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceResourceGroup\'])}/@{encodeURIComponent(\'Incident\')}/@{encodeURIComponent(body(\'Alert_-_Get_incident\')?[\'properties\']?[\'CaseNumber\'])}/Severity/@{encodeURIComponent(\'High\')}' - } - } - } - outputs: {} - } - parameters: { - '$connections': { - value: { - azuresentinel: { - connectionId: AzureSentinelConnection.id - connectionName: AzureSentinelConnectionName - id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${resourceGroup().location}/managedApis/azuresentinel' - } - } - } - } - } -} - -//Create Azure Activity solution for Sentinel -resource dataConnectorTemplateSpec1 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: dataConnectorTemplateSpecName1 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'DataConnector' - } - properties: { - description: 'Azure Activity data connector with template' - displayName: 'Azure Activity template' - } -} - -resource dataConnectorTemplateSpecName1_dataConnectorVersion1 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: dataConnectorTemplateSpec1 - name: '${dataConnectorVersion1}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'DataConnector' - } - properties: { - description: 'Azure Activity data connector with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: dataConnectorVersion1 - parameters: {} - variables: {} - resources: [ - { - name: '${workspace}/Microsoft.SecurityInsights/${_dataConnectorContentId1}' - apiVersion: '2021-03-01-preview' - type: 'Microsoft.OperationalInsights/workspaces/providers/dataConnectors' - location: workspace_location - kind: 'StaticUI' - properties: { - connectorUiConfig: { - id: _uiConfigId1 - title: 'Azure Activity' - publisher: 'Microsoft' - descriptionMarkdown: 'Azure Activity Log is a subscription log that provides insight into subscription-level events that occur in Azure, including events from Azure Resource Manager operational data, service health events, write operations taken on the resources in your subscription, and the status of activities performed in Azure. For more information, see the [Microsoft Sentinel documentation ](https://go.microsoft.com/fwlink/p/?linkid=2219695&wt.mc_id=sentinel_dataconnectordocs_content_cnl_csasci).' - graphQueries: [ - { - metricName: 'Total data received' - legend: 'AzureActivity' - baseQuery: 'AzureActivity' - } - ] - connectivityCriterias: [ - { - type: 'IsConnectedQuery' - value: [ - 'AzureActivity\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)' - ] - } - ] - dataTypes: [ - { - name: 'AzureActivity' - lastDataReceivedQuery: 'AzureActivity\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)' - } - ] - } - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/DataConnector-${last(split(_dataConnectorId1, '/'))}' - properties: { - parentId: extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', workspace), 'Microsoft.SecurityInsights/dataConnectors', _dataConnectorContentId1) - contentId: _dataConnectorContentId1 - kind: 'DataConnector' - version: dataConnectorVersion1 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource workspace_Microsoft_SecurityInsights_DataConnector_dataConnectorId1 'Microsoft.OperationalInsights/workspaces/providers/metadata@2022-01-01-preview' = { - name: '${workspace}/Microsoft.SecurityInsights/DataConnector-${last(split(_dataConnectorId1, '/'))}' - location: workspace_location - properties: { - parentId: extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', workspace), 'Microsoft.SecurityInsights/dataConnectors', _dataConnectorContentId1) - contentId: _dataConnectorContentId1 - kind: 'DataConnector' - version: dataConnectorVersion1 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - dependsOn: [ - sentinel - ] -} - -resource workspace_Microsoft_SecurityInsights_dataConnectorContentId1 'Microsoft.OperationalInsights/workspaces/providers/dataConnectors@2021-03-01-preview' = { - name: '${workspace}/Microsoft.SecurityInsights/${_dataConnectorContentId1}' - location: workspace_location - kind: 'StaticUI' - properties: { - connectorUiConfig: { - title: 'Azure Activity' - publisher: 'Microsoft' - descriptionMarkdown: 'Azure Activity Log is a subscription log that provides insight into subscription-level events that occur in Azure, including events from Azure Resource Manager operational data, service health events, write operations taken on the resources in your subscription, and the status of activities performed in Azure. For more information, see the [Microsoft Sentinel documentation ](https://go.microsoft.com/fwlink/p/?linkid=2219695&wt.mc_id=sentinel_dataconnectordocs_content_cnl_csasci).' - graphQueries: [ - { - metricName: 'Total data received' - legend: 'AzureActivity' - baseQuery: 'AzureActivity' - } - ] - dataTypes: [ - { - name: 'AzureActivity' - lastDataReceivedQuery: 'AzureActivity\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)' - } - ] - connectivityCriterias: [ - { - type: 'IsConnectedQuery' - value: [ - 'AzureActivity\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)' - ] - } - ] - id: _uiConfigId1 - } - } -} - -resource huntingQueryTemplateSpec1 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName1 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 1 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName1_huntingQueryVersion1 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec1 - name: '${huntingQueryVersion1}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'AnalyticsRulesAdministrativeOperations_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion1 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_1' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Microsoft Sentinel Analytics Rules Administrative Operations' - category: 'Hunting Queries' - query: 'let opValues = dynamic(["Microsoft.SecurityInsights/alertRules/write", "Microsoft.SecurityInsights/alertRules/delete"]);\n// Microsoft Sentinel Analytics - Rule Create / Update / Delete\nAzureActivity\n| where Category =~ "Administrative"\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created", "OK")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Identifies Microsoft Sentinel Analytics Rules administrative operations' - } - { - name: 'tactics' - value: 'Impact' - } - { - name: 'techniques' - value: 'T1496' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId1, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 1' - parentId: huntingQueryId1 - contentId: _huntingQuerycontentId1 - kind: 'HuntingQuery' - version: huntingQueryVersion1 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec2 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName2 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 2 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName2_huntingQueryVersion2 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec2 - name: '${huntingQueryVersion2}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'AnomalousAzureOperationModel_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion2 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_2' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Anomalous Azure Operation Hunting Model' - category: 'Hunting Queries' - query: '// When the detection window will end (3 days prior to now)\nlet startDetectDate = 3d;\n// When the detection window will start (now)\nlet endDetectDate = 0d;\n// When to start collecting data for detection\nlet startDate = startDetectDate + 30d;\n// Operation to monitor, in this case Run Command\nlet monitoredOps = dynamic([\'microsoft.compute/virtualmachines/runcommand/action\']);\n// The resource type to monitor, in this case virtual machines\nlet monitoredResource = pack_array(\'microsoft.compute/virtualmachines\');\nlet pair_probabilities_fl = (tbl:(*), A_col:string, B_col:string, scope_col:string)\n{\nlet T = (tbl | extend _A = column_ifexists(A_col, \'\'), _B = column_ifexists(B_col, \'\'), _scope = column_ifexists(scope_col, \'\'));\nlet countOnScope = T | summarize countAllOnScope = count() by _scope;\nlet probAB = T | summarize countAB = count() by _A, _B, _scope | join kind = leftouter (countOnScope) on _scope | extend P_AB = todouble(countAB)/countAllOnScope;\nlet probA = probAB | summarize countA = sum(countAB), countAllOnScope = max(countAllOnScope) by _A, _scope | extend P_A = todouble(countA)/countAllOnScope;\nlet probB = probAB | summarize countB = sum(countAB), countAllOnScope = max(countAllOnScope) by _B, _scope | extend P_B = todouble(countB)/countAllOnScope;\n probAB\n | join kind = leftouter (probA) on _A, _scope\n | join kind = leftouter (probB) on _B, _scope\n | extend P_AUB = P_A + P_B - P_AB\n , P_AIB = P_AB/P_B\n , P_BIA = P_AB/P_A\n | extend Lift_AB = P_AB/(P_A * P_B)\n , Jaccard_AB = P_AB/P_AUB\n | project _A, _B, _scope, floor(P_A, 0.00001), floor(P_B, 0.00001), floor(P_AB, 0.00001), floor(P_AUB, 0.00001), floor(P_AIB, 0.00001)\n , floor(P_BIA, 0.00001), floor(Lift_AB, 0.00001), floor(Jaccard_AB, 0.00001)\n | sort by _scope, _A, _B\n};\nlet eventsTable = materialize (\nAzureActivity\n| where TimeGenerated between (ago(startDate) .. ago(endDetectDate))\n| where isnotempty(CallerIpAddress)\n| where ActivityStatusValue has_any (\'Success\', \'Succeeded\')\n| extend ResourceId = iff(isempty(_ResourceId), ResourceId, _ResourceId)\n| extend splitOp = split(OperationNameValue, \'/\')\n| extend splitRes = split(ResourceId, \'/\')\n| project TimeGenerated , subscriptionId=SubscriptionId\n , ResourceProvider\n , ResourceName = tolower(tostring(splitRes[-1]))\n , OperationNameValue = tolower(OperationNameValue)\n , timeSlice = floor(TimeGenerated, 1d)\n , clientIp = tostring(CallerIpAddress)\n , Caller\n , isMonitoredOp = iff(OperationNameValue has_any (monitoredOps), 1, 0)\n , isMonitoredResource = iff(OperationNameValue has_any (monitoredResource), 1, 0)\n , CorrelationId\n| extend clientIpMask = format_ipv4_mask(clientIp, 16)\n);\nlet modelData = (\neventsTable\n| where TimeGenerated < ago(startDetectDate) and isnotempty(Caller) and isnotempty(subscriptionId)\n| summarize countEvents = count(), countMonRes = countif(isMonitoredResource == 1), counMonOp = countif(isMonitoredOp == 1)\n , firstSeen = min(timeSlice), firstSeenOnMonRes = minif(timeSlice, isMonitoredResource == 1), firstSeenOnMonOp = minif(timeSlice, isMonitoredOp == 1)\n by subscriptionId, Caller, clientIpMask\n);\nlet monOpProbs = materialize (\neventsTable\n| where TimeGenerated < ago(startDetectDate) and isnotempty(Caller) and isnotempty(subscriptionId)\n| invoke pair_probabilities_fl(\'Caller\', \'isMonitoredResource\',\'subscriptionId\')\n| where _B == 1\n| sort by P_AIB desc\n| extend rankOnMonRes = row_rank(P_AIB), sumBiggerCondProbs = row_cumsum(P_AIB) - P_AIB\n| extend avgBiggerCondProbs = floor(iff(rankOnMonRes > 1, sumBiggerCondProbs/(rankOnMonRes-1), max_of(0.0, prev(sumBiggerCondProbs))), 0.00001)\n| project-away sumBiggerCondProbs\n);\neventsTable\n| where TimeGenerated between (ago(startDetectDate) .. ago(endDetectDate))\n| join kind = leftouter (modelData | summarize countEventsPrincOnSub = sum(countEvents), countEventsMonResPrincOnSub = sum(countMonRes), countEventsMonOpPrincOnSub = sum(counMonOp)\n , firstSeenPrincOnSubs = min(firstSeen), firstSeenMonResPrincOnSubs = min(firstSeenOnMonRes), firstSeenMonOpPrincOnSubs = min(firstSeenOnMonOp) by subscriptionId, Caller) \n on subscriptionId, Caller\n| join kind = leftouter (modelData | summarize countEventsIpMaskOnSub = sum(countEvents), countEventsMonResIpMaskOnSub = sum(countMonRes), countEventsMonOpIpMaskOnSub = sum(counMonOp)\n , firstSeenIpMaskOnSubs = min(firstSeen), firstSeenMonResIpMaskOnSubs = min(firstSeenOnMonRes), firstSeenMonOpIpMaskOnSubs = min(firstSeenOnMonOp) by subscriptionId, clientIpMask) \n on subscriptionId, clientIpMask\n| join kind = leftouter (modelData | summarize countEventsOnSub = sum(countEvents), countEventsMonResOnSub = sum(countMonRes), countEventsMonOpOnSub = sum(counMonOp)\n , firstSeenOnSubs = min(firstSeen), firstSeenMonResOnSubs = min(firstSeenOnMonRes), firstSeenMonOpOnSubs = min(firstSeenOnMonOp)\n , countCallersOnSubs = dcount(Caller), countIpMasksOnSubs = dcount(clientIpMask) by subscriptionId)\n on subscriptionId \n| project-away subscriptionId1, Caller1, subscriptionId2\n| extend daysOnSubs = datetime_diff(\'day\', timeSlice, firstSeenOnSubs)\n| extend avgMonOpOnSubs = floor(1.0*countEventsMonOpOnSub/daysOnSubs, 0.01), avgMonResOnSubs = floor(1.0*countEventsMonResOnSub/daysOnSubs, 0.01)\n| join kind = leftouter(monOpProbs) on $left.subscriptionId == $right._scope, $left.Caller == $right._A\n| project-away _A, _B, _scope\n| sort by subscriptionId asc, TimeGenerated asc\n| extend rnOnSubs = row_number(1, subscriptionId != prev(subscriptionId))\n| sort by subscriptionId asc, Caller asc, TimeGenerated asc\n| extend rnOnCallerSubs = row_number(1, (subscriptionId != prev(subscriptionId) and (Caller != prev(Caller))))\n| extend newCaller = iff(isempty(firstSeenPrincOnSubs), 1, 0)\n , newCallerOnMonRes = iff(isempty(firstSeenMonResPrincOnSubs), 1, 0)\n , newIpMask = iff(isempty(firstSeenIpMaskOnSubs), 1, 0)\n , newIpMaskOnMonRes = iff(isempty(firstSeenMonResIpMaskOnSubs), 1, 0)\n , newMonOpOnSubs = iff(isempty(firstSeenMonResOnSubs), 1, 0)\n , anomCallerMonRes = iff(((Jaccard_AB <= 0.1) or (P_AIB <= 0.1)), 1, 0)\n| project TimeGenerated, subscriptionId, ResourceProvider, ResourceName, OperationNameValue, Caller, CorrelationId, ClientIP=clientIp, ActiveDaysOnSub=daysOnSubs, avgMonOpOnSubs, newCaller, newCallerOnMonRes, newIpMask, newIpMaskOnMonRes, newMonOpOnSubs, anomCallerMonRes, isMonitoredOp, isMonitoredResource\n| order by TimeGenerated\n| where isMonitoredOp == 1\n// Optional - focus only on monitored operations or monitored resource in detection window\n| where isMonitoredOp == 1\n//| where isMonitoredResource == 1\n' - version: 2 - tags: [ - { - name: 'description' - value: 'This query can be used during threat hunts to identify a range of different Azure Operation anomalies.\nThe query is heavily commented inline to explain operation. Anomalies covered are: New Caller, New Caller IP,\nNew Caller IP Range, Anomalous operation based on Jaccard index. By default this query is configured to detect\nanomalous Run Command operations. The operation and resource type to perform anomaly detection can be configured \nat the top of the query along with the detection window parameters' - } - { - name: 'tactics' - value: 'LateralMovement,CredentialAccess' - } - { - name: 'techniques' - value: 'T1570,T1078.004' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId2, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 2' - parentId: huntingQueryId2 - contentId: _huntingQuerycontentId2 - kind: 'HuntingQuery' - version: huntingQueryVersion2 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec3 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName3 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 3 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName3_huntingQueryVersion3 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec3 - name: '${huntingQueryVersion3}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Anomalous_Listing_Of_Storage_Keys_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion3 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_3' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Azure storage key enumeration' - category: 'Hunting Queries' - query: 'AzureActivity\n| where OperationNameValue =~ "microsoft.storage/storageaccounts/listkeys/action"\n| where ActivityStatusValue =~ "Succeeded" \n| join kind= inner (\n AzureActivity\n | where OperationNameValue =~ "microsoft.storage/storageaccounts/listkeys/action"\n | where ActivityStatusValue =~ "Succeeded" \n | project ExpectedIpAddress=CallerIpAddress, Caller \n | evaluate autocluster()\n) on Caller\n| where CallerIpAddress != ExpectedIpAddress\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), ResourceIds = make_set(ResourceId,100), ResourceIdCount = dcount(ResourceId) by OperationNameValue, Caller, CallerIpAddress\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Listing of storage keys is an interesting operation in Azure which might expose additional \nsecrets and PII to callers as well as granting access to VMs. While there are many benign operations of this\ntype, it would be interesting to see if the account performing this activity or the source IP address from \nwhich it is being done is anomalous. \nThe query below generates known clusters of ip address per caller, notice that users which only had single\noperations do not appear in this list as we cannot learn from it their normal activity (only based on a single\nevent). The activities for listing storage account keys is correlated with this learned \nclusters of expected activities and activity which is not expected is returned.' - } - { - name: 'tactics' - value: 'Discovery' - } - { - name: 'techniques' - value: 'T1087' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId3, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 3' - parentId: huntingQueryId3 - contentId: _huntingQuerycontentId3 - kind: 'HuntingQuery' - version: huntingQueryVersion3 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec4 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName4 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 4 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName4_huntingQueryVersion4 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec4 - name: '${huntingQueryVersion4}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'AzureAdministrationFromVPS_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion4 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_4' - location: workspace_location - properties: { - eTag: '*' - displayName: 'AzureActivity Administration From VPS Providers' - category: 'Hunting Queries' - query: 'let IP_Data = (externaldata(network:string)\n[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/VPS_Networks.csv"] with (format="csv"));\nAzureActivity\n| where CategoryValue =~ "Administrative"\n| evaluate ipv4_lookup(IP_Data, CallerIpAddress, network, return_unmatched = false)\n| summarize Operations = make_set(OperationNameValue), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by CallerIpAddress, Caller\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Looks for administrative actions in AzureActivity from known VPS provider network ranges.\nThis is not an exhaustive list of VPS provider ranges but covers some of the most prevalent providers observed.' - } - { - name: 'tactics' - value: 'InitialAccess' - } - { - name: 'techniques' - value: 'T1078' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId4, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 4' - parentId: huntingQueryId4 - contentId: _huntingQuerycontentId4 - kind: 'HuntingQuery' - version: huntingQueryVersion4 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec5 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName5 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 5 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName5_huntingQueryVersion5 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec5 - name: '${huntingQueryVersion5}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'AzureNSG_AdministrativeOperations_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion5 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_5' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Azure Network Security Group NSG Administrative Operations' - category: 'Hunting Queries' - query: 'let opValues = dynamic(["Microsoft.Network/networkSecurityGroups/write", "Microsoft.Network/networkSecurityGroups/delete"]);\n// Azure NSG Create / Update / Delete\nAzureActivity\n| where Category =~ "Administrative"\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created", "OK","Accepted")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Identifies a set of Azure NSG administrative and operational detection queries for hunting activities.' - } - { - name: 'tactics' - value: 'Impact' - } - { - name: 'techniques' - value: 'T1496' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId5, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 5' - parentId: huntingQueryId5 - contentId: _huntingQuerycontentId5 - kind: 'HuntingQuery' - version: huntingQueryVersion5 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec6 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName6 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 6 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName6_huntingQueryVersion6 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec6 - name: '${huntingQueryVersion6}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'AzureRunCommandFromAzureIP_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion6 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_6' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Azure VM Run Command executed from Azure IP address' - category: 'Hunting Queries' - query: 'let azure_ranges = externaldata(changeNumber: string, cloud: string, values: dynamic)\n["https://raw.githubusercontent.com/microsoft/mstic/master/PublicFeeds/MSFTIPRanges/ServiceTags_Public.json"] with(format=\'multijson\')\n| mv-expand values\n| extend Name = values.name, AddressPrefixes = values.properties.addressPrefixes\n| where Name startswith "WindowsVirtualDesktop"\n| mv-expand AddressPrefixes\n| summarize by tostring(AddressPrefixes);\nAzureActivity\n| where TimeGenerated > ago(30d)\n// Isolate run command actions\n| where OperationNameValue == "Microsoft.Compute/virtualMachines/runCommand/action"\n// Confirm that the operation impacted a virtual machine\n| where Authorization has "virtualMachines"\n// Each runcommand operation consists of three events when successful, Started, Accepted (or Rejected), Successful (or Failed).\n| summarize StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), max(CallerIpAddress), make_list(ActivityStatusValue) by CorrelationId, Authorization, Caller\n// Limit to Run Command executions that Succeeded\n| where list_ActivityStatusValue has "Succeeded"\n// Extract data from the Authorization field, allowing us to later extract the Caller (UPN) and CallerIpAddress\n| extend Authorization_d = parse_json(Authorization)\n| extend Scope = Authorization_d.scope\n| extend Scope_s = split(Scope, "/")\n| extend Subscription = tostring(Scope_s[2])\n| extend VirtualMachineName = tostring(Scope_s[-1])\n| project StartTime, EndTime, Subscription, VirtualMachineName, CorrelationId, Caller, CallerIpAddress=max_CallerIpAddress\n| evaluate ipv4_lookup(azure_ranges, CallerIpAddress, AddressPrefixes)\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Identifies any Azure VM Run Command operation executed from an Azure IP address.\nRun Command allows an attacker or legitimate user to execute arbitrary PowerShell\non a target VM. This technique has been seen in use by NOBELIUM.' - } - { - name: 'tactics' - value: 'LateralMovement,CredentialAccess' - } - { - name: 'techniques' - value: 'T1570,T1078.004' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId6, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 6' - parentId: huntingQueryId6 - contentId: _huntingQuerycontentId6 - kind: 'HuntingQuery' - version: huntingQueryVersion6 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec7 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName7 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 7 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName7_huntingQueryVersion7 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec7 - name: '${huntingQueryVersion7}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'AzureSentinelConnectors_AdministrativeOperations_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion7 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_7' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Microsoft Sentinel Connectors Administrative Operations' - category: 'Hunting Queries' - query: 'let opValues = dynamic(["Microsoft.SecurityInsights/dataConnectors/write", "Microsoft.SecurityInsights/dataConnectors/delete"]);\n// Microsoft Sentinel Data Connectors Update / Delete\nAzureActivity\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created", "OK")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Identifies a set of Microsoft Sentinel Data Connectors for administrative and operational detection queries for hunting activities.' - } - { - name: 'tactics' - value: 'Impact' - } - { - name: 'techniques' - value: 'T1496' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId7, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 7' - parentId: huntingQueryId7 - contentId: _huntingQuerycontentId7 - kind: 'HuntingQuery' - version: huntingQueryVersion7 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec8 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName8 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 8 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName8_huntingQueryVersion8 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec8 - name: '${huntingQueryVersion8}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'AzureSentinelWorkbooks_AdministrativeOperation_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion8 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_8' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Microsoft Sentinel Workbooks Administrative Operations' - category: 'Hunting Queries' - query: 'let opValues = dynamic(["microsoft.insights/workbooks/write", "microsoft.insights/workbooks/delete"]);\n// Microsoft Sentinel Workbook Create / Update / Delete\nAzureActivity\n| where Category =~ "Administrative"\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created", "OK")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Identifies set of Microsoft Sentinel Workbooks administrative operational detection queries for hunting activites' - } - { - name: 'tactics' - value: 'Impact' - } - { - name: 'techniques' - value: 'T1496' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId8, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 8' - parentId: huntingQueryId8 - contentId: _huntingQuerycontentId8 - kind: 'HuntingQuery' - version: huntingQueryVersion8 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec9 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName9 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 9 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName9_huntingQueryVersion9 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec9 - name: '${huntingQueryVersion9}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'AzureVirtualNetworkSubnets_AdministrativeOperationset_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion9 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_9' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Azure Virtual Network Subnets Administrative Operations' - category: 'Hunting Queries' - query: 'let opValues = dynamic(["Microsoft.Network/virtualNetworks/subnets/write","Microsoft.Network/virtualNetworks/subnets/delete"]);\n// Creating, Updating or Deleting Virtual Network Subnets\nAzureActivity\n| where CategoryValue =~ "Administrative"\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created","Accepted")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Identifies a set of Azure Virtual Network Subnets for administrative and operational detection queries for hunting activities.' - } - { - name: 'tactics' - value: 'Impact' - } - { - name: 'techniques' - value: 'T1496' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId9, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 9' - parentId: huntingQueryId9 - contentId: _huntingQuerycontentId9 - kind: 'HuntingQuery' - version: huntingQueryVersion9 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec10 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName10 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 10 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName10_huntingQueryVersion10 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec10 - name: '${huntingQueryVersion10}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Common_Deployed_Resources_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion10 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_10' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Common deployed resources' - category: 'Hunting Queries' - query: 'AzureActivity\n| where OperationNameValue has_any (@"deployments/write", @"virtualMachines/write") \n| where ActivityStatusValue =~ "Succeeded"\n| summarize by bin(TimeGenerated,1d), Resource, ResourceGroup, ResourceId, OperationNameValue, Caller\n| evaluate basket()\n| where isnotempty(Caller) and isnotempty(Resource) and isnotempty(TimeGenerated)\n| order by Percent desc, TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend AzureResource_0_ResourceId = ResourceId\n// remove comments below on filters if the goal is to see more common or more rare Resource, Resource Group and Caller combinations\n//| where Percent <= 40 // <-- more rare\n//| where Percent >= 60 // <-- more common\n' - version: 2 - tags: [ - { - name: 'description' - value: 'This query looks for common deployed resources (resource name and resource groups) and can be used\nin combination with other signals that show suspicious deployment to evaluate if the resource is one\nthat is commonly being deployed/created or unique.\nTo understand the basket() function better see - https://docs.microsoft.com/azure/data-explorer/kusto/query/basketplugin' - } - { - name: 'tactics' - value: 'Impact' - } - { - name: 'techniques' - value: 'T1496' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId10, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 10' - parentId: huntingQueryId10 - contentId: _huntingQuerycontentId10 - kind: 'HuntingQuery' - version: huntingQueryVersion10 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec11 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName11 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 11 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName11_huntingQueryVersion11 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec11 - name: '${huntingQueryVersion11}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Creating_Anomalous_Number_Of_Resources_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion11 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_11' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Creation of an anomalous number of resources' - category: 'Hunting Queries' - query: 'AzureActivity\n| where OperationNameValue in~ ("microsoft.compute/virtualMachines/write", "microsoft.resources/deployments/write")\n| where ActivityStatusValue == "Succeeded" \n| make-series dcount(ResourceId) default=0 on EventSubmissionTimestamp in range(ago(7d), now(), 1d) by Caller\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Looks for anomalous number of resources creation or deployment activities in azure activity log.\nIt is best to run this query on a look back period which is at least 7 days.' - } - { - name: 'tactics' - value: 'Impact' - } - { - name: 'techniques' - value: 'T1496' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId11, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 11' - parentId: huntingQueryId11 - contentId: _huntingQuerycontentId11 - kind: 'HuntingQuery' - version: huntingQueryVersion11 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec12 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName12 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 12 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName12_huntingQueryVersion12 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec12 - name: '${huntingQueryVersion12}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Granting_Permissions_to_Account_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion12 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_12' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Granting permissions to account' - category: 'Hunting Queries' - query: 'AzureActivity\n| where OperationName =~ "Create role assignment"\n| where ActivityStatus =~ "Succeeded" \n| project Caller, CallerIpAddress\n| evaluate basket()\n// Returns all the records from the left side and only matching records from the right side.\n| join kind=leftouter (AzureActivity\n| where OperationName =~ "Create role assignment"\n| where ActivityStatus =~ "Succeeded"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by Caller, CallerIpAddress)\non Caller, CallerIpAddress\n| project-away Caller1, CallerIpAddress1\n| where isnotempty(StartTime)\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Shows the most prevalent users who grant access to others on Azure resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.' - } - { - name: 'tactics' - value: 'Persistence,PrivilegeEscalation' - } - { - name: 'techniques' - value: 'T1098' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId12, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 12' - parentId: huntingQueryId12 - contentId: _huntingQuerycontentId12 - kind: 'HuntingQuery' - version: huntingQueryVersion12 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec13 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName13 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 13 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName13_huntingQueryVersion13 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec13 - name: '${huntingQueryVersion13}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'PortOpenedForAzureResource_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion13 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_13' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Port opened for an Azure Resource' - category: 'Hunting Queries' - query: 'let lookback = 7d;\nAzureActivity\n| where TimeGenerated >= ago(lookback)\n| where OperationNameValue has_any ("ipfilterrules", "securityRules", "publicIPAddresses", "firewallrules") and OperationNameValue endswith "write"\n// Choosing Accepted here because it has the Rule Attributes included\n| where ActivityStatusValue == "Accepted" \n// If there is publicIP info, include it\n| extend parsed_properties = parse_json(tostring(parse_json(Properties).responseBody)).properties\n| extend publicIPAddressVersion = case(Properties has_cs \'publicIPAddressVersion\',tostring(parsed_properties.publicIPAddressVersion),"")\n| extend publicIPAllocationMethod = case(Properties has_cs \'publicIPAllocationMethod\',tostring(parsed_properties.publicIPAllocationMethod),"")\n// Include rule attributes for context\n| extend access = case(Properties has_cs \'access\',tostring(parsed_properties.access),"")\n| extend description = case(Properties has_cs \'description\',tostring(parsed_properties.description),"")\n| extend destinationPortRange = case(Properties has_cs \'destinationPortRange\',tostring(parsed_properties.destinationPortRange),"")\n| extend direction = case(Properties has_cs \'direction\',tostring(parsed_properties.direction),"")\n| extend protocol = case(Properties has_cs \'protocol\',tostring(parsed_properties.protocol),"")\n| extend sourcePortRange = case(Properties has_cs \'sourcePortRange\',tostring(parsed_properties.sourcePortRange),"")\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), ResourceIds = make_set(_ResourceId,100) by Caller, CallerIpAddress, Resource, ResourceGroup, \nActivityStatusValue, ActivitySubstatus, SubscriptionId, access, description, destinationPortRange, direction, protocol, sourcePortRange, publicIPAddressVersion, publicIPAllocationMethod\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'Identifies what ports may have been opened for a given Azure Resource over the last 7 days' - } - { - name: 'tactics' - value: 'CommandAndControl,Impact' - } - { - name: 'techniques' - value: 'T1071,T1571,T1496' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId13, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 13' - parentId: huntingQueryId13 - contentId: _huntingQuerycontentId13 - kind: 'HuntingQuery' - version: huntingQueryVersion13 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource huntingQueryTemplateSpec14 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: huntingQueryTemplateSpecName14 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Azure Activity Hunting Query 14 with template' - displayName: 'Azure Activity Hunting Query template' - } -} - -resource huntingQueryTemplateSpecName14_huntingQueryVersion14 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: huntingQueryTemplateSpec14 - name: '${huntingQueryVersion14}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'HuntingQuery' - } - properties: { - description: 'Rare_Custom_Script_Extension_HuntingQueries Hunting Query with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: huntingQueryVersion14 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.OperationalInsights/savedSearches' - apiVersion: '2020-08-01' - name: 'Azure_Activity_Hunting_Query_14' - location: workspace_location - properties: { - eTag: '*' - displayName: 'Rare Custom Script Extension' - category: 'Hunting Queries' - query: 'let starttime = todatetime(\'{{StartTimeISO}}\');\nlet endtime = todatetime(\'{{EndTimeISO}}\');\nlet Lookback = starttime - 14d;\nlet CustomScriptExecution = AzureActivity\n| where TimeGenerated >= Lookback\n| where OperationName =~ "Create or Update Virtual Machine Extension"\n| extend parsed_properties = parse_json(Properties)\n| extend Settings = tostring((parse_json(tostring(parsed_properties.responseBody)).properties).settings)\n| parse Settings with * \'fileUris":[\' FileURI "]" *\n| parse Settings with * \'commandToExecute":\' commandToExecute \'}\' *\n| extend message_ = tostring((parse_json(tostring(parsed_properties.statusMessage)).error).message);\nlet LookbackCustomScriptExecution = CustomScriptExecution\n| where TimeGenerated >= Lookback and TimeGenerated < starttime\n| where isnotempty(FileURI) and isnotempty(commandToExecute)\n| summarize max(TimeGenerated), OperationCount = count() by Caller, Resource, CallerIpAddress, FileURI, commandToExecute;\nlet CurrentCustomScriptExecution = CustomScriptExecution\n| where TimeGenerated between (starttime..endtime)\n| where isnotempty(FileURI) and isnotempty(commandToExecute)\n| project TimeGenerated, ActivityStatus, OperationId, CorrelationId, ResourceId, CallerIpAddress, Caller, OperationName, Resource, ResourceGroup, FileURI, commandToExecute, FailureMessage = message_, HTTPRequest, Settings;\nlet RareCustomScriptExecution = CurrentCustomScriptExecution\n| join kind= leftanti (LookbackCustomScriptExecution) on Caller, CallerIpAddress, FileURI, commandToExecute;\nlet IPCheck = RareCustomScriptExecution\n| summarize arg_max(TimeGenerated, OperationName), OperationIds = make_set(OperationId,100), CallerIpAddresses = make_set(CallerIpAddress,100) by ActivityStatus, CorrelationId, ResourceId, Caller, Resource, ResourceGroup, FileURI, commandToExecute, FailureMessage\n| extend IPArray = array_length(CallerIpAddresses);\n//Get IPs for later summarization so all associated CorrelationIds and Caller actions have an IP. Success and Fails do not always have IP\nlet multiIP = IPCheck | where IPArray > 1\n| mv-expand CallerIpAddresses | extend CallerIpAddress = tostring(CallerIpAddresses)\n| where isnotempty(CallerIpAddresses);\nlet singleIP = IPCheck | where IPArray <= 1\n| mv-expand CallerIpAddresses | extend CallerIpAddress = tostring(CallerIpAddresses);\nlet FullDetails = singleIP | union multiIP;\n//Get IP address associated with successes and fails with no IP listed\nlet IPList = FullDetails | where isnotempty(CallerIpAddress) | summarize by CorrelationId, Caller, CallerIpAddress;\nlet EmptyIP = FullDetails | where isempty(CallerIpAddress) | project-away CallerIpAddress;\nlet IpJoin = EmptyIP | join kind= leftouter (IPList) on CorrelationId, Caller | project-away CorrelationId1, Caller1;\nlet nonEmptyIP = FullDetails | where isnotempty(CallerIpAddress);\nnonEmptyIP | union IpJoin\n// summarize all activities with a given CorrelationId and Caller together so we can provide a singular result\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), ActivityStatusSet = make_set(ActivityStatus,100), OperationIds = make_set(OperationIds,100), FailureMessages = make_set(FailureMessage,100) by CorrelationId, ResourceId, CallerIpAddress, Caller, Resource, ResourceGroup, FileURI, commandToExecute\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' - version: 2 - tags: [ - { - name: 'description' - value: 'The Custom Script Extension downloads and executes scripts on Azure virtual machines. This extension is useful for post deployment configuration, software installation, or any other configuration or management tasks.\n Scripts could be downloaded from external links, Azure storage, GitHub, or provided to the Azure portal at extension run time. This could also be used maliciously by an attacker.\n The query tries to identify rare custom script extensions that have been executed in your environment' - } - { - name: 'tactics' - value: 'Execution' - } - { - name: 'techniques' - value: 'T1059' - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId14, '/'))}' - properties: { - description: 'Azure Activity Hunting Query 14' - parentId: huntingQueryId14 - contentId: _huntingQuerycontentId14 - kind: 'HuntingQuery' - version: huntingQueryVersion14 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec1 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName1 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 1 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName1_analyticRuleVersion1 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec1 - name: '${analyticRuleVersion1}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'AADHybridHealthADFSNewServer_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion1 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId1 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Azure AD Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/' - displayName: 'Azure Active Directory Hybrid Health AD FS New Server' - enabled: false - query: 'AzureActivity\n| where CategoryValue =~ \'Administrative\'\n| where ResourceProviderValue =~ \'Microsoft.ADHybridHealthService\'\n| where _ResourceId has \'AdFederationService\'\n| where OperationNameValue =~ \'Microsoft.ADHybridHealthService/services/servicemembers/action\'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| project-away claimsJson\n' - queryFrequency: 'P1D' - queryPeriod: 'P1D' - severity: 'Medium' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'DefenseEvasion' - ] - techniques: [ - 'T1578' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId1, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 1' - parentId: analyticRuleId1 - contentId: _analyticRulecontentId1 - kind: 'AnalyticsRule' - version: analyticRuleVersion1 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec2 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName2 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 2 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName2_analyticRuleVersion2 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec2 - name: '${analyticRuleVersion2}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'AADHybridHealthADFSServiceDelete_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion2 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId2 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'This detection uses AzureActivity logs (Administrative category) to identify the deletion of an Azure AD Hybrid Health AD FS service instance in a tenant.\nA threat actor can create a new AD Health ADFS service and create a fake server to spoof AD FS signing logs.\nThe health AD FS service can then be deleted after it is no longer needed via HTTP requests to Azure.\nMore information is available in this blog https://o365blog.com/post/hybridhealthagent/' - displayName: 'Azure Active Directory Hybrid Health AD FS Service Delete' - enabled: false - query: 'AzureActivity\n| where CategoryValue =~ \'Administrative\'\n| where ResourceProviderValue =~ \'Microsoft.ADHybridHealthService\'\n| where _ResourceId has \'AdFederationService\'\n| where OperationNameValue =~ \'Microsoft.ADHybridHealthService/services/delete\'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| project-away claimsJson\n' - queryFrequency: 'P1D' - queryPeriod: 'P1D' - severity: 'Medium' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'DefenseEvasion' - ] - techniques: [ - 'T1578' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId2, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 2' - parentId: analyticRuleId2 - contentId: _analyticRulecontentId2 - kind: 'AnalyticsRule' - version: analyticRuleVersion2 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec3 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName3 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 3 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName3_analyticRuleVersion3 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec3 - name: '${analyticRuleVersion3}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'AADHybridHealthADFSSuspApp_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion3 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId3 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'This detection uses AzureActivity logs (Administrative category) to identify a suspicious application adding a server instance to an Azure AD Hybrid Health AD FS service or deleting the AD FS service instance.\nUsually the Azure AD Connect Health Agent application with ID cf6d7e68-f018-4e0a-a7b3-126e053fb88d and ID cb1056e2-e479-49de-ae31-7812af012ed8 is used to perform those operations.' - displayName: 'Azure Active Directory Hybrid Health AD FS Suspicious Application' - enabled: false - query: '// Azure AD Connect Health Agent - cf6d7e68-f018-4e0a-a7b3-126e053fb88d\n// Azure Active Directory Connect - cb1056e2-e479-49de-ae31-7812af012ed8\nlet appList = dynamic([\'cf6d7e68-f018-4e0a-a7b3-126e053fb88d\',\'cb1056e2-e479-49de-ae31-7812af012ed8\']);\nlet operationNamesList = dynamic([\'Microsoft.ADHybridHealthService/services/servicemembers/action\',\'Microsoft.ADHybridHealthService/services/delete\']);\nAzureActivity\n| where CategoryValue =~ \'Administrative\'\n| where ResourceProviderValue =~ \'Microsoft.ADHybridHealthService\'\n| where _ResourceId has \'AdFederationService\'\n| where OperationNameValue in~ (operationNamesList)\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| where AppId !in (appList)\n| project-away claimsJson\n' - queryFrequency: 'P1D' - queryPeriod: 'P1D' - severity: 'Medium' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'CredentialAccess' - 'DefenseEvasion' - ] - techniques: [ - 'T1528' - 'T1550' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId3, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 3' - parentId: analyticRuleId3 - contentId: _analyticRulecontentId3 - kind: 'AnalyticsRule' - version: analyticRuleVersion3 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec4 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName4 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 4 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName4_analyticRuleVersion4 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec4 - name: '${analyticRuleVersion4}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Creating_Anomalous_Number_Of_Resources_detection_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion4 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId4 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'Indicates when an anomalous number of VM creations or deployment activities occur in Azure via the AzureActivity log. This query generates the baseline pattern of cloud resource creation by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.' - displayName: 'Suspicious number of resource creation or deployment activities' - enabled: false - query: 'let szOperationNames = dynamic(["microsoft.compute/virtualMachines/write", "microsoft.resources/deployments/write"]);\nlet starttime = 7d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TimeSeriesData =\nAzureActivity\n| where TimeGenerated between (startofday(ago(starttime)) .. startofday(now()))\n| where OperationNameValue in~ (szOperationNames)\n| project TimeGenerated, Caller \n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller; \nTimeSeriesData\n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, \'linefit\')\n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long) \n| where TimeGenerated >= startofday(ago(endtime))\n| where anomalies > 0 and baseline > 0\n| project Caller, TimeGenerated, Total, baseline, anomalies, score\n| join (AzureActivity\n| where TimeGenerated > startofday(ago(endtime)) \n| where OperationNameValue in~ (szOperationNames)\n| summarize make_set(OperationNameValue,100), make_set(_ResourceId,100), make_set(CallerIpAddress,100) by bin(TimeGenerated, timeframe), Caller\n) on TimeGenerated, Caller\n| mv-expand CallerIpAddress=set_CallerIpAddress\n| project-away Caller1\n| extend Name = iif(Caller has \'@\',tostring(split(Caller,\'@\',0)[0]),"")\n| extend UPNSuffix = iif(Caller has \'@\',tostring(split(Caller,\'@\',1)[0]),"")\n| extend AadUserId = iif(Caller !has \'@\',Caller,"")\n' - queryFrequency: 'P1D' - queryPeriod: 'P7D' - severity: 'Medium' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'Impact' - ] - techniques: [ - 'T1496' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - { - columnName: 'AadUserId' - identifier: 'AadUserId' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId4, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 4' - parentId: analyticRuleId4 - contentId: _analyticRulecontentId4 - kind: 'AnalyticsRule' - version: analyticRuleVersion4 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec5 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName5 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 5 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName5_analyticRuleVersion5 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec5 - name: '${analyticRuleVersion5}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Creation_of_Expensive_Computes_in_Azure_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion5 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId5 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions' - displayName: 'Creation of expensive computes in Azure' - enabled: false - query: 'let tokens = dynamic(["416","208","192","128","120","96","80","72","64","48","44","40","g5","gs5","g4","gs4","nc12","nc24","nv24"]);\nlet operationList = dynamic(["microsoft.compute/virtualmachines/write", "microsoft.resources/deployments/write"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith "Accept"\n| where Properties has \'vmSize\'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| where vmSize has_any (tokens)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' - queryFrequency: 'P1D' - queryPeriod: 'P1D' - severity: 'Low' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 1 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'DefenseEvasion' - ] - techniques: [ - 'T1578' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId5, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 5' - parentId: analyticRuleId5 - contentId: _analyticRulecontentId5 - kind: 'AnalyticsRule' - version: analyticRuleVersion5 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec6 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName6 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 6 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName6_analyticRuleVersion6 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec6 - name: '${analyticRuleVersion6}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Granting_Permissions_To_Account_detection_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion6 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId6 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'Identifies IPs from which users grant access to other users on Azure resources and alerts when a previously unseen source IP address is used.' - displayName: 'Suspicious granting of permissions to an account' - enabled: false - query: 'let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\nlet AzureBuiltInRole = externaldata(Role:string,RoleDescription:string,ID:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/AzureBuiltInRole.csv"] with (format="csv", ignoreFirstRecord=True);\nlet createRoleAssignmentActivity = AzureActivity\n| where OperationNameValue =~ "microsoft.authorization/roleassignments/write";\nlet RoleAssignedActivity = createRoleAssignmentActivity \n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, bin(TimeGenerated, 1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don\'t have matches from the left.\n| join kind = rightanti ( \ncreateRoleAssignmentActivity\n| where TimeGenerated > ago(endtime)\n| extend parsed_property = tostring(parse_json(Properties).requestbody)\n| extend PrincipalId = case(parsed_property has_cs \'PrincipalId\',parse_json(parsed_property).Properties.PrincipalId, parsed_property has_cs \'principalId\',parse_json(parsed_property).properties.principalId,"")\n| extend PrincipalType = case(parsed_property has_cs \'PrincipalType\',parse_json(parsed_property).Properties.PrincipalType, parsed_property has_cs \'principalType\',parse_json(parsed_property).properties.principalType, "")\n| extend Scope = case(parsed_property has_cs \'Scope\',parse_json(parsed_property).Properties.Scope, parsed_property has_cs \'scope\',parse_json(parsed_property).properties.scope,"")\n| extend RoleAddedDetails = case(parsed_property has_cs \'RoleDefinitionId\',parse_json(parsed_property).Properties.RoleDefinitionId,parsed_property has_cs \'roleDefinitionId\',parse_json(parsed_property).properties.roleDefinitionId,"")\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated), ActivityStatusValue = make_set(ActivityStatusValue), CorrelationId = make_set(CorrelationId), ActivityCountByCallerIPAddress = count() \nby ResourceId, CallerIpAddress, Caller, OperationNameValue, Resource, ResourceGroup, PrincipalId, PrincipalType, Scope, RoleAddedDetails\n) on CallerIpAddress, Caller\n| extend timestamp = StartTimeUtc, AccountCustomEntity = Caller, IPCustomEntity = CallerIpAddress;\nlet RoleAssignedActivitywithRoleDetails = RoleAssignedActivity\n| extend RoleAssignedID = tostring(split(RoleAddedDetails, "/")[-1])\n// Returns all matching records from left and right sides.\n| join kind = inner (AzureBuiltInRole \n) on $left.RoleAssignedID == $right.ID;\nlet CallerIPCountSummary = RoleAssignedActivitywithRoleDetails | summarize AssignmentCountbyCaller = count() by Caller, CallerIpAddress;\nlet RoleAssignedActivityWithCount = RoleAssignedActivitywithRoleDetails | join kind = inner (CallerIPCountSummary | project Caller, AssignmentCountbyCaller, CallerIpAddress) on Caller, CallerIpAddress;\nRoleAssignedActivityWithCount\n| summarize arg_max(StartTimeUtc, *) by PrincipalId, RoleAssignedID\n// \tReturns all the records from the left side and only matching records from the right side.\n| join kind = leftouter( IdentityInfo\n| summarize arg_max(TimeGenerated, *) by AccountObjectId\n) on $left.PrincipalId == $right.AccountObjectId\n// Check if assignment count is greater than the threshold.\n| where AssignmentCountbyCaller >= alertOperationThreshold\n| project ActivityTimeStamp, OperationNameValue, Caller, CallerIpAddress, PrincipalId, RoleAssignedID, RoleAddedDetails, Role, RoleDescription, AccountUPN, AccountCreationTime, GroupMembership, UserType, ActivityStatusValue, ResourceGroup, PrincipalType, Scope, CorrelationId, timestamp, AccountCustomEntity, IPCustomEntity, AssignmentCountbyCaller\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' - queryFrequency: 'P1D' - queryPeriod: 'P14D' - severity: 'Medium' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - { - dataTypes: [ - 'IdentityInfo' - ] - connectorId: 'BehaviorAnalytics' - } - ] - tactics: [ - 'Persistence' - 'PrivilegeEscalation' - ] - techniques: [ - 'T1098' - 'T1548' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId6, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 6' - parentId: analyticRuleId6 - contentId: _analyticRulecontentId6 - kind: 'AnalyticsRule' - version: analyticRuleVersion6 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec7 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName7 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 7 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName7_analyticRuleVersion7 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec7 - name: '${analyticRuleVersion7}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'NRT-AADHybridHealthADFSNewServer_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion7 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId7 - apiVersion: '2022-04-01-preview' - kind: 'NRT' - location: workspace_location - properties: { - description: 'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Azure AD Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/' - displayName: 'NRT Azure Active Directory Hybrid Health AD FS New Server' - enabled: false - query: 'AzureActivity\n| where CategoryValue =~ \'Administrative\'\n| where ResourceProviderValue =~ \'Microsoft.ADHybridHealthService\'\n| where _ResourceId has \'AdFederationService\'\n| where OperationNameValue =~ \'Microsoft.ADHybridHealthService/services/servicemembers/action\'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| project-away claimsJson\n' - severity: 'Medium' - suppressionDuration: 'PT1H' - suppressionEnabled: false - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'DefenseEvasion' - ] - techniques: [ - 'T1578' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId7, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 7' - parentId: analyticRuleId7 - contentId: _analyticRulecontentId7 - kind: 'AnalyticsRule' - version: analyticRuleVersion7 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec8 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName8 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 8 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName8_analyticRuleVersion8 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec8 - name: '${analyticRuleVersion8}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'NRT_Creation_of_Expensive_Computes_in_Azure_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion8 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId8 - apiVersion: '2022-04-01-preview' - kind: 'NRT' - location: workspace_location - properties: { - description: 'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions' - displayName: 'NRT Creation of expensive computes in Azure' - enabled: false - query: 'let tokens = dynamic(["416","208","192","128","120","96","80","72","64","48","44","40","g5","gs5","g4","gs4","nc12","nc24","nv24"]);\nlet operationList = dynamic(["microsoft.compute/virtualmachines/write", "microsoft.resources/deployments/write"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith "Accept"\n| where Properties has \'vmSize\'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| where vmSize has_any (tokens)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' - severity: 'Medium' - suppressionDuration: 'PT1H' - suppressionEnabled: false - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'DefenseEvasion' - ] - techniques: [ - 'T1578' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId8, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 8' - parentId: analyticRuleId8 - contentId: _analyticRulecontentId8 - kind: 'AnalyticsRule' - version: analyticRuleVersion8 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec9 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName9 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 9 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName9_analyticRuleVersion9 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec9 - name: '${analyticRuleVersion9}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'New-CloudShell-User_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion9 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId9 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell.' - displayName: 'New CloudShell User' - enabled: false - query: 'let match_window = 3m;\nAzureActivity\n| where ResourceGroup has "cloud-shell"\n| where (OperationNameValue =~ "Microsoft.Storage/storageAccounts/listKeys/action")\n| where ActivityStatusValue =~ "Success"\n| extend TimeKey = bin(TimeGenerated, match_window), AzureIP = CallerIpAddress\n| join kind = inner\n(AzureActivity\n| where ResourceGroup has "cloud-shell"\n| where (OperationNameValue =~ "Microsoft.Storage/storageAccounts/write")\n| extend TimeKey = bin(TimeGenerated, match_window), UserIP = CallerIpAddress\n) on Caller, TimeKey\n| summarize count() by TimeKey, Caller, ResourceGroup, SubscriptionId, TenantId, AzureIP, UserIP, HTTPRequest, Type, Properties, CategoryValue, OperationList = strcat(OperationNameValue, \' , \', OperationNameValue1)\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' - queryFrequency: 'P1D' - queryPeriod: 'P1D' - severity: 'Low' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'Execution' - ] - techniques: [ - 'T1059' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'UserIP' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId9, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 9' - parentId: analyticRuleId9 - contentId: _analyticRulecontentId9 - kind: 'AnalyticsRule' - version: analyticRuleVersion9 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec10 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName10 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 10 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName10_analyticRuleVersion10 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec10 - name: '${analyticRuleVersion10}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'NewResourceGroupsDeployedTo_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion10 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId10 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller.' - displayName: 'Suspicious Resource deployment' - enabled: false - query: '// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet szOperationNames = dynamic(["Microsoft.Compute/virtualMachines/write", "Microsoft.Resources/deployments/write", "Microsoft.Resources/subscriptions/resourceGroups/write"]);\nlet starttime = 14d;\nlet endtime = 1d;\nlet RareCaller = AzureActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n// Returns all the records from the right side that don\'t have matches from the left.\n| join kind=rightantisemi (\nAzureActivity\n| where TimeGenerated > ago(endtime)\n| where OperationNameValue in~ (szOperationNames)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated,100), ActivityStatusValue = make_set(ActivityStatusValue,100), CorrelationIds = make_set(CorrelationId,100), ResourceGroups = make_set(ResourceGroup,100), ResourceIds = make_set(_ResourceId,100), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue) on CallerIpAddress, Caller, OperationNameValue;\nRareCaller\n| extend Name = iif(Caller has \'@\',tostring(split(Caller,\'@\',0)[0]),"")\n| extend UPNSuffix = iif(Caller has \'@\',tostring(split(Caller,\'@\',1)[0]),"")\n| extend AadUserId = iif(Caller !has \'@\',Caller,"")\n' - queryFrequency: 'P1D' - queryPeriod: 'P14D' - severity: 'Low' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'Impact' - ] - techniques: [ - 'T1496' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - { - columnName: 'AadUserId' - identifier: 'AadUserId' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId10, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 10' - parentId: analyticRuleId10 - contentId: _analyticRulecontentId10 - kind: 'AnalyticsRule' - version: analyticRuleVersion10 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec11 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName11 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 11 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName11_analyticRuleVersion11 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec11 - name: '${analyticRuleVersion11}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'RareOperations_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion11 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId11 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name \'Create or Update Snapshot\', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk.' - displayName: 'Rare subscription-level operations in Azure' - enabled: false - query: 'let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\n// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet SensitiveOperationList = dynamic(["microsoft.compute/snapshots/write", "microsoft.network/networksecuritygroups/write", "microsoft.storage/storageaccounts/listkeys/action"]);\nlet SensitiveActivity = AzureActivity\n| where OperationNameValue in~ (SensitiveOperationList) or OperationNameValue hassuffix "listkeys/action"\n| where ActivityStatusValue =~ "Success";\nSensitiveActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don\'t have matches from the left\n| join kind = rightanti (\nSensitiveActivity\n| where TimeGenerated >= ago(endtime)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_list(TimeGenerated), ActivityStatusValue = make_list(ActivityStatusValue), CorrelationIds = make_list(CorrelationId), ResourceGroups = make_list(ResourceGroup), ResourceIds = make_list(_ResourceId), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue\n| where ActivityCountByCallerIPAddress >= alertOperationThreshold\n) on CallerIpAddress, Caller, OperationNameValue\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' - queryFrequency: 'P1D' - queryPeriod: 'P14D' - severity: 'Low' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'CredentialAccess' - 'Persistence' - ] - techniques: [ - 'T1003' - 'T1098' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - ] - } - { - entityType: 'IP' - fieldMappings: [ - { - columnName: 'CallerIpAddress' - identifier: 'Address' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId11, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 11' - parentId: analyticRuleId11 - contentId: _analyticRulecontentId11 - kind: 'AnalyticsRule' - version: analyticRuleVersion11 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource analyticRuleTemplateSpec12 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: analyticRuleTemplateSpecName12 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'Azure Activity Analytics Rule 12 with template' - displayName: 'Azure Activity Analytics Rule template' - } -} - -resource analyticRuleTemplateSpecName12_analyticRuleVersion12 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: analyticRuleTemplateSpec12 - name: '${analyticRuleVersion12}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'AnalyticsRule' - } - properties: { - description: 'TimeSeriesAnomaly_Mass_Cloud_Resource_Deletions_AnalyticalRules Analytics Rule with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: analyticRuleVersion12 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.SecurityInsights/AlertRuleTemplates' - name: analyticRulecontentId12 - apiVersion: '2022-04-01-preview' - kind: 'Scheduled' - location: workspace_location - properties: { - description: 'This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.' - displayName: 'Mass Cloud resource deletions Time Series Anomaly' - enabled: false - query: 'let starttime = 14d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TotalEventsThreshold = 25;\nlet TimeSeriesData = AzureActivity \n| where TimeGenerated between (startofday(ago(starttime))..startofday(now())) \n| where OperationNameValue endswith "delete" \n| project TimeGenerated, Caller \n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller;\nTimeSeriesData \n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, \'linefit\') \n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long) \n| where TimeGenerated >= startofday(ago(endtime)) \n| where anomalies > 0 \n| project Caller, TimeGenerated, Total, baseline, anomalies, score \n| where Total > TotalEventsThreshold and baseline > 0 \n| join (AzureActivity \n| where TimeGenerated > startofday(ago(endtime)) \n| where OperationNameValue endswith "delete" \n| summarize count(), make_set(OperationNameValue,100), make_set(_ResourceId,100) by bin(TimeGenerated, timeframe), Caller ) on TimeGenerated, Caller \n| extend Name = iif(Caller has \'@\',tostring(split(Caller,\'@\',0)[0]),"")\n| extend UPNSuffix = iif(Caller has \'@\',tostring(split(Caller,\'@\',1)[0]),"")\n| extend AadUserId = iif(Caller !has \'@\',Caller,"")\n' - queryFrequency: 'P1D' - queryPeriod: 'P14D' - severity: 'Medium' - suppressionDuration: 'PT1H' - suppressionEnabled: false - triggerOperator: 'GreaterThan' - triggerThreshold: 0 - status: 'Available' - requiredDataConnectors: [ - { - dataTypes: [ - 'AzureActivity' - ] - connectorId: 'AzureActivity' - } - ] - tactics: [ - 'Impact' - ] - techniques: [ - 'T1485' - ] - entityMappings: [ - { - entityType: 'Account' - fieldMappings: [ - { - columnName: 'Name' - identifier: 'Name' - } - { - columnName: 'UPNSuffix' - identifier: 'UPNSuffix' - } - { - columnName: 'AadUserId' - identifier: 'AadUserId' - } - ] - } - ] - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId12, '/'))}' - properties: { - description: 'Azure Activity Analytics Rule 12' - parentId: analyticRuleId12 - contentId: _analyticRulecontentId12 - kind: 'AnalyticsRule' - version: analyticRuleVersion12 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - } - } - ] - } - } -} - -resource workbookTemplateSpec1 'Microsoft.Resources/templateSpecs@2022-02-01' = { - name: workbookTemplateSpecName1 - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'Workbook' - } - properties: { - description: 'Azure Activity Workbook with template' - displayName: 'Azure Activity workbook template' - } -} - -resource workbookTemplateSpecName1_workbookVersion1 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { - parent: workbookTemplateSpec1 - name: '${workbookVersion1}' - location: workspace_location - tags: { - 'hidden-sentinelWorkspaceId': workspaceResourceId - 'hidden-sentinelContentType': 'Workbook' - } - properties: { - description: 'AzureActivityWorkbook with template version 2.0.6' - mainTemplate: { - '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' - contentVersion: workbookVersion1 - parameters: {} - variables: {} - resources: [ - { - type: 'Microsoft.Insights/workbooks' - name: workbookContentId1 - location: workspace_location - kind: 'shared' - apiVersion: '2021-08-01' - metadata: { - description: 'Gain extensive insight into your organization\'s Azure Activity by analyzing, and correlating all user operations and events.\nYou can learn about all user operations, trends, and anomalous changes over time.\nThis workbook gives you the ability to drill down into caller activities and summarize detected failure and warning events.' - } - properties: { - displayName: workbook1_name - serializedData: '{"version":"Notebook/1.0","items":[{"type":9,"content":{"version":"KqlParameterItem/1.0","query":"","crossComponentResources":"[variables(\'TemplateEmptyArray\')]","parameters":[{"id":"52bfbd84-1639-480c-bda5-bfc87fd81832","version":"KqlParameterItem/1.0","name":"TimeRange","type":4,"isRequired":true,"value":{"durationMs":604800000},"typeSettings":{"selectableValues":[{"durationMs":300000},{"durationMs":900000},{"durationMs":1800000},{"durationMs":3600000},{"durationMs":14400000},{"durationMs":43200000},{"durationMs":86400000},{"durationMs":172800000},{"durationMs":259200000},{"durationMs":604800000},{"durationMs":1209600000},{"durationMs":2419200000},{"durationMs":2592000000},{"durationMs":5184000000},{"durationMs":7776000000}]}},{"id":"eeb5dcf9-e898-46af-9c12-d91d97e13cd3","version":"KqlParameterItem/1.0","name":"Caller","type":2,"isRequired":true,"multiSelect":true,"quote":"\'","delimiter":",","query":"AzureActivity\\r\\n| summarize by Caller","value":["value::all"],"typeSettings":{"additionalResourceOptions":["value::all"],"selectAllValue":"All"},"timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces"},{"id":"46375a76-7ae1-4d7e-9082-4191531198a9","version":"KqlParameterItem/1.0","name":"ResourceGroup","type":2,"isRequired":true,"multiSelect":true,"quote":"\'","delimiter":",","query":"AzureActivity\\r\\n| summarize by ResourceGroup","value":["value::all"],"typeSettings":{"resourceTypeFilter":{"microsoft.resources/resourcegroups":true},"additionalResourceOptions":["value::all"],"selectAllValue":"All"},"timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces"}],"style":"pills","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces"},"name":"parameters - 2"},{"type":3,"content":{"version":"KqlItem/1.0","query":"let data = AzureActivity\\r\\n| where \\"{Caller:lable}\\" == \\"All\\" or \\"{Caller:lable}\\" == \\"All\\" or Caller in ({Caller})\\r\\n| where \\"{ResourceGroup:lable}\\" == \\"All\\" or \\"{ResourceGroup:lable}\\" == \\"All\\" or ResourceGroup in ({ResourceGroup});\\r\\ndata\\r\\n| summarize Count = count() by ResourceGroup\\r\\n| join kind = fullouter (datatable(ResourceGroup:string)[\'Medium\', \'high\', \'low\']) on ResourceGroup\\r\\n| project ResourceGroup = iff(ResourceGroup == \'\', ResourceGroup1, ResourceGroup), Count = iff(ResourceGroup == \'\', 0, Count)\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by ResourceGroup)\\r\\n on ResourceGroup\\r\\n| project-away ResourceGroup1, TimeGenerated\\r\\n| extend ResourceGroups = ResourceGroup\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count() \\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend ResourceGroup = \'All\', ResourceGroups = \'*\' \\r\\n)\\r\\n| order by Count desc\\r\\n| take 10","size":4,"exportToExcelOptions":"visible","title":"Top 10 active resource groups","timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces","visualization":"tiles","tileSettings":{"titleContent":{"columnMatch":"ResourceGroup","formatter":1,"formatOptions":{"showIcon":true}},"leftContent":{"columnMatch":"Count","formatter":12,"formatOptions":{"palette":"auto","showIcon":true},"numberFormat":{"unit":17,"options":{"maximumSignificantDigits":3,"maximumFractionDigits":2}}},"secondaryContent":{"columnMatch":"Trend","formatter":9,"formatOptions":{"palette":"blueOrange","showIcon":true}},"showBorder":false}},"name":"query - 3"},{"type":3,"content":{"version":"KqlItem/1.0","query":"AzureActivity\\r\\n| where \\"{Caller:lable}\\" == \\"All\\" or Caller in ({Caller})\\r\\n| where \\"{ResourceGroup:lable}\\" == \\"All\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize deletions = countif(OperationNameValue hassuffix \\"delete\\"), creations = countif(OperationNameValue hassuffix \\"write\\"), updates = countif(OperationNameValue hassuffix \\"write\\"), Activities = count(OperationNameValue) by bin_at(TimeGenerated, 1h, now())\\r\\n","size":0,"exportToExcelOptions":"visible","title":"Activities over time","color":"gray","timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces","visualization":"linechart","graphSettings":{"type":0}},"name":"query - 1"},{"type":3,"content":{"version":"KqlItem/1.0","query":"AzureActivity\\r\\n| where \\"{Caller:lable}\\" == \\"All\\" or Caller in ({Caller})\\r\\n| where \\"{ResourceGroup:lable}\\" == \\"All\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize deletions = countif(OperationNameValue hassuffix \\"Delete\\"), creations = countif(OperationNameValue hassuffix \\"write\\"), updates = countif(OperationNameValue hassuffix \\"write\\"), Activities = count() by Caller\\r\\n","size":1,"exportToExcelOptions":"visible","title":"Caller activities","timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces","gridSettings":{"formatters":[{"columnMatch":"Caller","formatter":0,"formatOptions":{"showIcon":true}},{"columnMatch":"deletions","formatter":4,"formatOptions":{"showIcon":true,"aggregation":"Count"}},{"columnMatch":"creations","formatter":4,"formatOptions":{"palette":"purple","showIcon":true,"aggregation":"Count"}},{"columnMatch":"updates","formatter":4,"formatOptions":{"palette":"gray","showIcon":true,"aggregation":"Count"}},{"columnMatch":"Activities","formatter":4,"formatOptions":{"palette":"greenDark","linkTarget":"GenericDetails","linkIsContextBlade":true,"showIcon":true,"aggregation":"Count","workbookContext":{"componentIdSource":"workbook","resourceIdsSource":"workbook","templateIdSource":"static","templateId":"https://go.microsoft.com/fwlink/?linkid=874159&resourceId=%2Fsubscriptions%2F44e4eff8-1fcb-4a22-a7d6-992ac7286382%2FresourceGroups%2FSOC&featureName=Workbooks&itemId=%2Fsubscriptions%2F44e4eff8-1fcb-4a22-a7d6-992ac7286382%2Fresourcegroups%2Fsoc%2Fproviders%2Fmicrosoft.insights%2Fworkbooks%2F4c195aec-747f-40bb-addb-934acb3ec646&name=CiscoASA&func=NavigateToPortalFeature&type=workbook","typeSource":"workbook","gallerySource":"workbook"}}}],"sortBy":[{"itemKey":"$gen_bar_updates_3","sortOrder":2}],"labelSettings":"[variables(\'TemplateEmptyArray\')]"}},"name":"query - 1"},{"type":3,"content":{"version":"KqlItem/1.0","query":"AzureActivity \\r\\n| where \\"{Caller:lable}\\" == \\"All\\" or Caller in ({Caller})\\r\\n| where \\"{ResourceGroup:lable}\\" == \\"All\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize Informational = countif(Level == \\"Informational\\"), Warning = countif(Level == \\"Warning\\"), Error = countif(Level == \\"Error\\") by bin_at(TimeGenerated, 1h, now())\\r\\n","size":0,"exportToExcelOptions":"visible","title":"Activities by log level over time","color":"redBright","timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces","visualization":"scatterchart","tileSettings":{"showBorder":false},"graphSettings":{"type":2,"topContent":{"columnMatch":"Error","formatter":12,"formatOptions":{"showIcon":true}},"hivesContent":{"columnMatch":"TimeGenerated","formatter":1,"formatOptions":{"showIcon":true}},"nodeIdField":"Error","sourceIdField":"Error","targetIdField":"Error","nodeSize":"[variables(\'blanks\')]","staticNodeSize":100,"colorSettings":"[variables(\'blanks\')]","groupByField":"TimeGenerated","hivesMargin":5}},"name":"query - 4"}],"fromTemplateId":"sentinel-AzureActivity","$schema":"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json"}\r\n' - version: '1.0' - sourceId: workspaceResourceId - category: 'sentinel' - } - } - { - type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' - apiVersion: '2022-01-01-preview' - name: '${workspace}/Microsoft.SecurityInsights/Workbook-${last(split(workbookId1, '/'))}' - properties: { - description: '@{workbookKey=AzureActivityWorkbook; logoFileName=azureactivity_logo.svg; description=Gain extensive insight into your organization\'s Azure Activity by analyzing, and correlating all user operations and events.\nYou can learn about all user operations, trends, and anomalous changes over time.\nThis workbook gives you the ability to drill down into caller activities and summarize detected failure and warning events.; dataTypesDependencies=System.Object[]; dataConnectorsDependencies=System.Object[]; previewImagesFileNames=System.Object[]; version=2.0.0; title=Azure Activity; templateRelativePath=AzureActivity.json; subtitle=; provider=Microsoft}.description' - parentId: workbookId1 - contentId: _workbookContentId1 - kind: 'Workbook' - version: workbookVersion1 - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - tier: 'Microsoft' - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - link: 'https://support.microsoft.com/' - } - dependencies: { - operator: 'AND' - criteria: [ - { - contentId: 'AzureActivity' - kind: 'DataType' - } - { - contentId: 'AzureActivity' - kind: 'DataConnector' - } - ] - } - } - } - ] - } - } -} - -resource workspace_Microsoft_SecurityInsights_solutionId 'Microsoft.OperationalInsights/workspaces/providers/metadata@2022-01-01-preview' = { - location: workspace_location - properties: { - version: '2.0.6' - kind: 'Solution' - contentSchemaVersion: '2.0.0' - contentId: _solutionId - parentId: _solutionId - source: { - kind: 'Solution' - name: 'Azure Activity' - sourceId: _solutionId - } - author: { - name: 'Microsoft' - email: _email - } - support: { - name: 'Microsoft Corporation' - email: 'support@microsoft.com' - tier: 'Microsoft' - link: 'https://support.microsoft.com/' - } - dependencies: { - operator: 'AND' - criteria: [ - { - kind: 'DataConnector' - contentId: _dataConnectorContentId1 - version: dataConnectorVersion1 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId1 - version: huntingQueryVersion1 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId2 - version: huntingQueryVersion2 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId3 - version: huntingQueryVersion3 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId4 - version: huntingQueryVersion4 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId5 - version: huntingQueryVersion5 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId6 - version: huntingQueryVersion6 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId7 - version: huntingQueryVersion7 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId8 - version: huntingQueryVersion8 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId9 - version: huntingQueryVersion9 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId10 - version: huntingQueryVersion10 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId11 - version: huntingQueryVersion11 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId12 - version: huntingQueryVersion12 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId13 - version: huntingQueryVersion13 - } - { - kind: 'HuntingQuery' - contentId: _huntingQuerycontentId14 - version: huntingQueryVersion14 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId1 - version: analyticRuleVersion1 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId2 - version: analyticRuleVersion2 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId3 - version: analyticRuleVersion3 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId4 - version: analyticRuleVersion4 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId5 - version: analyticRuleVersion5 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId6 - version: analyticRuleVersion6 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId7 - version: analyticRuleVersion7 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId8 - version: analyticRuleVersion8 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId9 - version: analyticRuleVersion9 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId10 - version: analyticRuleVersion10 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId11 - version: analyticRuleVersion11 - } - { - kind: 'AnalyticsRule' - contentId: analyticRulecontentId12 - version: analyticRuleVersion12 - } - { - kind: 'Workbook' - contentId: _workbookContentId1 - version: workbookVersion1 - } - ] - } - firstPublishDate: '2022-04-18' - providers: [ - 'Microsoft' - ] - categories: { - domains: [ - 'IT Operations' - ] - } - } - name: '${workspace}/Microsoft.SecurityInsights/${_solutionId}' -} - -output hostname string = pip.properties.dnsSettings.fqdn +//On the Logic Apps Designer blade, click the first Connections step. +//ensure that the entry in the Tenant drop down list contains your Azure AD tenant name and Sign-in. + +param rgName string = 'AZ500LAB131415' + +param defenderAutoProvision string = 'On' +param defenderAppServicesPricingTier string = 'Standard' +param defenderVirtualMachinesPricingTier string = 'Standard' +param defenderSqlServersPricingTier string = 'Standard' +param defenderStorageAccountsPricingTier string = 'Standard' +param defenderDnsPricingTier string ='Standard' +param defenderArmPricingTier string = 'Standard' +param PlaybookName string = 'Change-Incident-Severity' + +//Replace the value +param UserName string = '@' + +@description('Username for the Virtual Machine.') +param adminUsername string = 'localadmin' + +@description('Password for the Virtual Machine.') +@minLength(12) +@secure() +param adminPassword string + +@description('Unique DNS Name for the Public IP used to access the Virtual Machine.') +param dnsLabelPrefix string = toLower('${vmName}-${uniqueString(resourceGroup().id, vmName)}') + +@description('Name for the Public IP used to access the Virtual Machine.') +param publicIpName string = 'myPublicIpAddress' + +@description('Allocation method for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Dynamic' + 'Static' +]) +param publicIPAllocationMethod string = 'Static' + +@description('SKU for the Public IP used to access the Virtual Machine.') +@allowed([ + 'Basic' + 'Standard' +]) +param publicIpSku string = 'Standard' + +@description('The Windows version for the VM. This will pick a fully patched image of this given Windows version.') +@allowed([ +'2016-Datacenter' +'2022-datacenter' +'2022-datacenter-azure-edition-core' +]) +param OSVersion string = '2022-datacenter-azure-edition-core' + +@description('Size of the virtual machine.') +param vmSize string = 'Standard_D2s_v5' + +@description('Location for all resources.') +param location string = 'eastus' + +@description('Name of the virtual machine.') +param vmName string = 'myVM' + +param logAnalyticsWorkspaceName string = 'la-${uniqueString(resourceGroup().id)}' + +@description('Region to deploy solution resources -- separate from location selection}') +param workspace_location string = 'eastus' + +@description('Workspace name for Log Analytics where Microsoft Sentinel is setup') +param workspace string = logAnalyticsWorkspaceName + +@description('Name for the workbook') +@minLength(1) +param workbook1_name string = 'Azure Activity' + +var AzureSentinelConnectionName = 'azuresentinel-${PlaybookName}' +var solutionName = 'SecurityInsights(${logAnalyticsWorkspace.name})' +var storageAccountName = 'bootdiags${uniqueString(resourceGroup().id)}' +var nicName = 'myVMNic' +var addressPrefix = '192.168.0.0/16' +var subnetName = 'mySubnet' +var subnetPrefix = '192.168.1.0/24' +var virtualNetworkName = 'myVnet' +var networkSecurityGroupName = 'myNetworkSecurityGroup' +var primaryKey = logAnalyticsWorkspace.listKeys().primarySharedKey + + + +var solutionId = 'azuresentinel.azure-sentinel-solution-azureactivity' +var _solutionId = solutionId +var email = 'support@microsoft.com' +var _email = email +var workspaceResourceId = resourceId('microsoft.OperationalInsights/Workspaces', workspace) +var uiConfigId1 = 'AzureActivity' +var _uiConfigId1 = uiConfigId1 +var dataConnectorContentId1 = 'AzureActivity' +var _dataConnectorContentId1 = dataConnectorContentId1 +var dataConnectorId1 = extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', workspace), 'Microsoft.SecurityInsights/dataConnectors', _dataConnectorContentId1) +var _dataConnectorId1 = dataConnectorId1 +var dataConnectorTemplateSpecName1 = '${workspace}-dc-${uniqueString(_dataConnectorContentId1)}' +var dataConnectorVersion1 = '2.0.0' +var huntingQueryVersion1 = '2.0.1' +var huntingQuerycontentId1 = 'ef7ef44e-6129-4d8e-94fe-b5530415d8e5' +var _huntingQuerycontentId1 = huntingQuerycontentId1 +var huntingQueryId1 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId1) +var huntingQueryTemplateSpecName1 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId1)}' +var huntingQueryVersion2 = '2.0.0' +var huntingQuerycontentId2 = '43cb0347-bdcc-4e83-af5a-cebbd03971d8' +var _huntingQuerycontentId2 = huntingQuerycontentId2 +var huntingQueryId2 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId2) +var huntingQueryTemplateSpecName2 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId2)}' +var huntingQueryVersion3 = '2.0.1' +var huntingQuerycontentId3 = '5d2399f9-ea5c-4e67-9435-1fba745f3a39' +var _huntingQuerycontentId3 = huntingQuerycontentId3 +var huntingQueryId3 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId3) +var huntingQueryTemplateSpecName3 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId3)}' +var huntingQueryVersion4 = '2.0.1' +var huntingQuerycontentId4 = '1b8779c9-abf2-444f-a21f-437b8f90ac4a' +var _huntingQuerycontentId4 = huntingQuerycontentId4 +var huntingQueryId4 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId4) +var huntingQueryTemplateSpecName4 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId4)}' +var huntingQueryVersion5 = '2.0.1' +var huntingQuerycontentId5 = 'e94d6756-981c-4f02-9a81-d006d80c8b41' +var _huntingQuerycontentId5 = huntingQuerycontentId5 +var huntingQueryId5 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId5) +var huntingQueryTemplateSpecName5 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId5)}' +var huntingQueryVersion6 = '2.1.1' +var huntingQuerycontentId6 = 'efe843ca-3ce7-4896-9f8b-f2c374ae6527' +var _huntingQuerycontentId6 = huntingQuerycontentId6 +var huntingQueryId6 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId6) +var huntingQueryTemplateSpecName6 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId6)}' +var huntingQueryVersion7 = '2.0.1' +var huntingQuerycontentId7 = '17201aa8-0916-4078-a020-7ea3a9262889' +var _huntingQuerycontentId7 = huntingQuerycontentId7 +var huntingQueryId7 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId7) +var huntingQueryTemplateSpecName7 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId7)}' +var huntingQueryVersion8 = '2.0.1' +var huntingQuerycontentId8 = '5a1f9655-c893-4091-8dc0-7f11d7676506' +var _huntingQuerycontentId8 = huntingQuerycontentId8 +var huntingQueryId8 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId8) +var huntingQueryTemplateSpecName8 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId8)}' +var huntingQueryVersion9 = '2.0.1' +var huntingQuerycontentId9 = '57784ba5-7791-422e-916f-65ef94fe1dbb' +var _huntingQuerycontentId9 = huntingQuerycontentId9 +var huntingQueryId9 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId9) +var huntingQueryTemplateSpecName9 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId9)}' +var huntingQueryVersion10 = '2.0.1' +var huntingQuerycontentId10 = '0278e3b8-9899-45c5-8928-700cd80d2d80' +var _huntingQuerycontentId10 = huntingQuerycontentId10 +var huntingQueryId10 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId10) +var huntingQueryTemplateSpecName10 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId10)}' +var huntingQueryVersion11 = '2.0.1' +var huntingQuerycontentId11 = 'a09e6368-065b-4f1e-a4ce-b1b3a64b493b' +var _huntingQuerycontentId11 = huntingQuerycontentId11 +var huntingQueryId11 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId11) +var huntingQueryTemplateSpecName11 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId11)}' +var huntingQueryVersion12 = '2.0.1' +var huntingQuerycontentId12 = '860cda84-765b-4273-af44-958b7cca85f7' +var _huntingQuerycontentId12 = huntingQuerycontentId12 +var huntingQueryId12 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId12) +var huntingQueryTemplateSpecName12 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId12)}' +var huntingQueryVersion13 = '2.0.1' +var huntingQuerycontentId13 = '9e146876-e303-49af-b847-b029d1a66852' +var _huntingQuerycontentId13 = huntingQuerycontentId13 +var huntingQueryId13 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId13) +var huntingQueryTemplateSpecName13 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId13)}' +var huntingQueryVersion14 = '2.0.1' +var huntingQuerycontentId14 = '81fd68a2-9ad6-4a1c-7bd7-18efe5c99081' +var _huntingQuerycontentId14 = huntingQuerycontentId14 +var huntingQueryId14 = resourceId('Microsoft.OperationalInsights/savedSearches', _huntingQuerycontentId14) +var huntingQueryTemplateSpecName14 = '${workspace}-hq-${uniqueString(_huntingQuerycontentId14)}' +var analyticRuleVersion1 = '2.0.1' +var analyticRulecontentId1 = '88f453ff-7b9e-45bb-8c12-4058ca5e44ee' +var _analyticRulecontentId1 = analyticRulecontentId1 +var analyticRuleId1 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId1) +var analyticRuleTemplateSpecName1 = '${workspace}-ar-${uniqueString(_analyticRulecontentId1)}' +var analyticRuleVersion2 = '2.0.1' +var analyticRulecontentId2 = '86a036b2-3686-42eb-b417-909fc0867771' +var _analyticRulecontentId2 = analyticRulecontentId2 +var analyticRuleId2 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId2) +var analyticRuleTemplateSpecName2 = '${workspace}-ar-${uniqueString(_analyticRulecontentId2)}' +var analyticRuleVersion3 = '2.0.1' +var analyticRulecontentId3 = 'd9938c3b-16f9-444d-bc22-ea9a9110e0fd' +var _analyticRulecontentId3 = analyticRulecontentId3 +var analyticRuleId3 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId3) +var analyticRuleTemplateSpecName3 = '${workspace}-ar-${uniqueString(_analyticRulecontentId3)}' +var analyticRuleVersion4 = '2.0.3' +var analyticRulecontentId4 = '361dd1e3-1c11-491e-82a3-bb2e44ac36ba' +var _analyticRulecontentId4 = analyticRulecontentId4 +var analyticRuleId4 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId4) +var analyticRuleTemplateSpecName4 = '${workspace}-ar-${uniqueString(_analyticRulecontentId4)}' +var analyticRuleVersion5 = '2.0.1' +var analyticRulecontentId5 = '9736e5f1-7b6e-4bfb-a708-e53ff1d182c3' +var _analyticRulecontentId5 = analyticRulecontentId5 +var analyticRuleId5 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId5) +var analyticRuleTemplateSpecName5 = '${workspace}-ar-${uniqueString(_analyticRulecontentId5)}' +var analyticRuleVersion6 = '2.0.1' +var analyticRulecontentId6 = 'b2c15736-b9eb-4dae-8b02-3016b6a45a32' +var _analyticRulecontentId6 = analyticRulecontentId6 +var analyticRuleId6 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId6) +var analyticRuleTemplateSpecName6 = '${workspace}-ar-${uniqueString(_analyticRulecontentId6)}' +var analyticRuleVersion7 = '2.0.1' +var analyticRulecontentId7 = 'ec491363-5fe7-4eff-b68e-f42dcb76fcf6' +var _analyticRulecontentId7 = analyticRulecontentId7 +var analyticRuleId7 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId7) +var analyticRuleTemplateSpecName7 = '${workspace}-ar-${uniqueString(_analyticRulecontentId7)}' +var analyticRuleVersion8 = '2.0.1' +var analyticRulecontentId8 = '56fe0db0-6779-46fa-b3c5-006082a53064' +var _analyticRulecontentId8 = analyticRulecontentId8 +var analyticRuleId8 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId8) +var analyticRuleTemplateSpecName8 = '${workspace}-ar-${uniqueString(_analyticRulecontentId8)}' +var analyticRuleVersion9 = '2.0.2' +var analyticRulecontentId9 = '6d7214d9-4a28-44df-aafb-0910b9e6ae3e' +var _analyticRulecontentId9 = analyticRulecontentId9 +var analyticRuleId9 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId9) +var analyticRuleTemplateSpecName9 = '${workspace}-ar-${uniqueString(_analyticRulecontentId9)}' +var analyticRuleVersion10 = '2.0.2' +var analyticRulecontentId10 = '9fb57e58-3ed8-4b89-afcf-c8e786508b1c' +var _analyticRulecontentId10 = analyticRulecontentId10 +var analyticRuleId10 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId10) +var analyticRuleTemplateSpecName10 = '${workspace}-ar-${uniqueString(_analyticRulecontentId10)}' +var analyticRuleVersion11 = '2.0.2' +var analyticRulecontentId11 = '23de46ea-c425-4a77-b456-511ae4855d69' +var _analyticRulecontentId11 = analyticRulecontentId11 +var analyticRuleId11 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId11) +var analyticRuleTemplateSpecName11 = '${workspace}-ar-${uniqueString(_analyticRulecontentId11)}' +var analyticRuleVersion12 = '2.0.2' +var analyticRulecontentId12 = 'ed43bdb7-eaab-4ea4-be52-6951fcfa7e3b' +var _analyticRulecontentId12 = analyticRulecontentId12 +var analyticRuleId12 = resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', analyticRulecontentId12) +var analyticRuleTemplateSpecName12 = '${workspace}-ar-${uniqueString(_analyticRulecontentId12)}' +var TemplateEmptyArray = json('[]') +var blanks = replace('b', 'b', '') +var workbookVersion1 = '2.0.0' +var workbookContentId1 = 'AzureActivityWorkbook' +var workbookId1 = resourceId('Microsoft.Insights/workbooks', workbookContentId1) +var workbookTemplateSpecName1 = '${workspace}-wb-${uniqueString(_workbookContentId1)}' +var _workbookContentId1 = workbookContentId1 + +// Deploy an Azure virtual machine with a public IP address and a network security group +resource stg 'Microsoft.Storage/storageAccounts@2021-04-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'Storage' +} + +resource pip 'Microsoft.Network/publicIPAddresses@2021-02-01' = { + name: publicIpName + location: location + sku: { + name: publicIpSku + } + properties: { + publicIPAllocationMethod: publicIPAllocationMethod + dnsSettings: { + domainNameLabel: dnsLabelPrefix + } + } +} + +resource securityGroup 'Microsoft.Network/networkSecurityGroups@2021-02-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'allow-3389' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '3389' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + { + name: 'allow-http' + properties: { + priority: 1100 + access: 'Allow' + direction: 'Inbound' + destinationPortRange: '80' + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + } + } + ] + } +} + +resource vn 'Microsoft.Network/virtualNetworks@2021-02-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: subnetName + properties: { + addressPrefix: subnetPrefix + networkSecurityGroup: { + id: securityGroup.id + } + } + } + ] + } +} + +resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = { + name: nicName + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + publicIPAddress: { + id: pip.id + } + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', vn.name, subnetName) + } + } + } + ] + } +} + +resource vm 'Microsoft.Compute/virtualMachines@2021-03-01' = { + name: vmName + location: location + properties: { + hardwareProfile: { + vmSize: vmSize + } + osProfile: { + computerName: vmName + adminUsername: adminUsername + adminPassword: adminPassword + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: OSVersion + version: 'latest' + } + osDisk: { + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'StandardSSD_LRS' + } + } + dataDisks: [ + { + diskSizeGB: 1023 + lun: 0 + createOption: 'Empty' + } + ] + } + networkProfile: { + networkInterfaces: [ + { + id: nic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + storageUri: stg.properties.primaryEndpoints.blob + } + } + } +} + +// Create a Log Analytics workspace +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: logAnalyticsWorkspaceName + location: location + properties: any({ + retentionInDays: 30 + features: { + searchVersion: 1 + } + sku: { + name: 'PerGB2018' + } + }) +} + +// Enable the Log Analytics virtual machine extension +resource vmExtension 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { + parent: vm + name: 'Microsoft.Insights.LogAnalyticsAgent' + location: location + properties: { + publisher: 'Microsoft.Azure.Monitor' + type: 'AzureMonitorWindowsAgent' + autoUpgradeMinorVersion: true + typeHandlerVersion: '1.14' + settings: { + workspaceId: logAnalyticsWorkspace.id + } + protectedSettings: { + workspaceKey: primaryKey + } + } +} + +//Enable Sentinel +resource sentinel 'Microsoft.OperationsManagement/solutions@2015-11-01-preview' = { + name: solutionName + location: location + properties: { + workspaceResourceId: logAnalyticsWorkspace.id + } + plan: { + name: solutionName + publisher: 'Microsoft' + product: 'OMSGallery/SecurityInsights' + promotionCode: '' + } +} + +//Enable Defender for Cloud +module defenderForCloud 'defender-for-cloud.bicep' = { + scope: subscription() + name: 'defenderForCloud' + params: { + scope: subscription().id + workspaceId: logAnalyticsWorkspace.id + autoProvision: defenderAutoProvision + virtualMachinesPricingTier: defenderVirtualMachinesPricingTier + sqlServersPricingTier: defenderSqlServersPricingTier + storageAccountsPricingTier: defenderStorageAccountsPricingTier + appServicesPricingTier: defenderAppServicesPricingTier + dnsPricingTier: defenderDnsPricingTier + armPricingTier: defenderArmPricingTier + } +} + + +//Create Playbook and Sentinel connection +resource AzureSentinelConnection 'Microsoft.Web/connections@2016-06-01' = { + name: AzureSentinelConnectionName + location: location + properties: { + displayName: UserName + customParameterValues: {} + api: { + id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${resourceGroup().location}/managedApis/azuresentinel' + } + } +} + +resource Playbook 'Microsoft.Logic/workflows@2019-05-01' = { + name: PlaybookName + location: location + tags: { + LogicAppsCategory: 'security' + } + properties: { + state: 'Enabled' + definition: { + '$schema': 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#' + contentVersion: '1.0.0.0' + parameters: { + '$connections': { + defaultValue: {} + type: 'Object' + } + } + triggers: { + When_a_response_to_an_Azure_Sentinel_alert_is_triggered: { + type: 'ApiConnectionWebhook' + inputs: { + body: { + callback_url: '@{listCallbackUrl()}' + } + host: { + connection: { + name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']' + } + } + path: '/subscribe' + } + } + } + actions: { + 'Alert_-_Get_accounts': { + runAfter: { + 'Alert_-_Get_incident': [ + 'Succeeded' + ] + } + type: 'ApiConnection' + inputs: { + body: '@triggerBody()?[\'Entities\']' + host: { + connection: { + name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']' + } + } + method: 'post' + path: '/entities/account' + } + } + 'Alert_-_Get_incident': { + runAfter: {} + type: 'ApiConnection' + inputs: { + host: { + connection: { + name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']' + } + } + method: 'get' + path: '/Cases/@{encodeURIComponent(triggerBody()?[\'SystemAlertId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceSubscriptionId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceResourceGroup\'])}' + } + } + Change_incident_severity_2: { + runAfter: { + 'Alert_-_Get_accounts': [ + 'Succeeded' + ] + } + type: 'ApiConnection' + inputs: { + host: { + connection: { + name: '@parameters(\'$connections\')[\'azuresentinel\'][\'connectionId\']' + } + } + method: 'put' + path: '/Case/@{encodeURIComponent(triggerBody()?[\'WorkspaceSubscriptionId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceId\'])}/@{encodeURIComponent(triggerBody()?[\'WorkspaceResourceGroup\'])}/@{encodeURIComponent(\'Incident\')}/@{encodeURIComponent(body(\'Alert_-_Get_incident\')?[\'properties\']?[\'CaseNumber\'])}/Severity/@{encodeURIComponent(\'High\')}' + } + } + } + outputs: {} + } + parameters: { + '$connections': { + value: { + azuresentinel: { + connectionId: AzureSentinelConnection.id + connectionName: AzureSentinelConnectionName + id: '/subscriptions/${subscription().subscriptionId}/providers/Microsoft.Web/locations/${resourceGroup().location}/managedApis/azuresentinel' + } + } + } + } + } +} + +//Create Azure Activity solution for Sentinel +resource dataConnectorTemplateSpec1 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: dataConnectorTemplateSpecName1 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'DataConnector' + } + properties: { + description: 'Azure Activity data connector with template' + displayName: 'Azure Activity template' + } +} + +resource dataConnectorTemplateSpecName1_dataConnectorVersion1 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: dataConnectorTemplateSpec1 + name: '${dataConnectorVersion1}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'DataConnector' + } + properties: { + description: 'Azure Activity data connector with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: dataConnectorVersion1 + parameters: {} + variables: {} + resources: [ + { + name: '${workspace}/Microsoft.SecurityInsights/${_dataConnectorContentId1}' + apiVersion: '2021-03-01-preview' + type: 'Microsoft.OperationalInsights/workspaces/providers/dataConnectors' + location: workspace_location + kind: 'StaticUI' + properties: { + connectorUiConfig: { + id: _uiConfigId1 + title: 'Azure Activity' + publisher: 'Microsoft' + descriptionMarkdown: 'Azure Activity Log is a subscription log that provides insight into subscription-level events that occur in Azure, including events from Azure Resource Manager operational data, service health events, write operations taken on the resources in your subscription, and the status of activities performed in Azure. For more information, see the [Microsoft Sentinel documentation ](https://go.microsoft.com/fwlink/p/?linkid=2219695&wt.mc_id=sentinel_dataconnectordocs_content_cnl_csasci).' + graphQueries: [ + { + metricName: 'Total data received' + legend: 'AzureActivity' + baseQuery: 'AzureActivity' + } + ] + connectivityCriterias: [ + { + type: 'IsConnectedQuery' + value: [ + 'AzureActivity\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)' + ] + } + ] + dataTypes: [ + { + name: 'AzureActivity' + lastDataReceivedQuery: 'AzureActivity\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)' + } + ] + } + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/DataConnector-${last(split(_dataConnectorId1, '/'))}' + properties: { + parentId: extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', workspace), 'Microsoft.SecurityInsights/dataConnectors', _dataConnectorContentId1) + contentId: _dataConnectorContentId1 + kind: 'DataConnector' + version: dataConnectorVersion1 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource workspace_Microsoft_SecurityInsights_DataConnector_dataConnectorId1 'Microsoft.OperationalInsights/workspaces/providers/metadata@2022-01-01-preview' = { + name: '${workspace}/Microsoft.SecurityInsights/DataConnector-${last(split(_dataConnectorId1, '/'))}' + location: workspace_location + properties: { + parentId: extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', workspace), 'Microsoft.SecurityInsights/dataConnectors', _dataConnectorContentId1) + contentId: _dataConnectorContentId1 + kind: 'DataConnector' + version: dataConnectorVersion1 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + dependsOn: [ + sentinel + ] +} + +resource workspace_Microsoft_SecurityInsights_dataConnectorContentId1 'Microsoft.OperationalInsights/workspaces/providers/dataConnectors@2021-03-01-preview' = { + name: '${workspace}/Microsoft.SecurityInsights/${_dataConnectorContentId1}' + location: workspace_location + kind: 'StaticUI' + properties: { + connectorUiConfig: { + title: 'Azure Activity' + publisher: 'Microsoft' + descriptionMarkdown: 'Azure Activity Log is a subscription log that provides insight into subscription-level events that occur in Azure, including events from Azure Resource Manager operational data, service health events, write operations taken on the resources in your subscription, and the status of activities performed in Azure. For more information, see the [Microsoft Sentinel documentation ](https://go.microsoft.com/fwlink/p/?linkid=2219695&wt.mc_id=sentinel_dataconnectordocs_content_cnl_csasci).' + graphQueries: [ + { + metricName: 'Total data received' + legend: 'AzureActivity' + baseQuery: 'AzureActivity' + } + ] + dataTypes: [ + { + name: 'AzureActivity' + lastDataReceivedQuery: 'AzureActivity\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)' + } + ] + connectivityCriterias: [ + { + type: 'IsConnectedQuery' + value: [ + 'AzureActivity\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)' + ] + } + ] + id: _uiConfigId1 + } + } +} + +resource huntingQueryTemplateSpec1 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName1 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 1 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName1_huntingQueryVersion1 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec1 + name: '${huntingQueryVersion1}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'AnalyticsRulesAdministrativeOperations_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion1 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_1' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Microsoft Sentinel Analytics Rules Administrative Operations' + category: 'Hunting Queries' + query: 'let opValues = dynamic(["Microsoft.SecurityInsights/alertRules/write", "Microsoft.SecurityInsights/alertRules/delete"]);\n// Microsoft Sentinel Analytics - Rule Create / Update / Delete\nAzureActivity\n| where Category =~ "Administrative"\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created", "OK")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Identifies Microsoft Sentinel Analytics Rules administrative operations' + } + { + name: 'tactics' + value: 'Impact' + } + { + name: 'techniques' + value: 'T1496' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId1, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 1' + parentId: huntingQueryId1 + contentId: _huntingQuerycontentId1 + kind: 'HuntingQuery' + version: huntingQueryVersion1 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec2 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName2 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 2 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName2_huntingQueryVersion2 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec2 + name: '${huntingQueryVersion2}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'AnomalousAzureOperationModel_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion2 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_2' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Anomalous Azure Operation Hunting Model' + category: 'Hunting Queries' + query: '// When the detection window will end (3 days prior to now)\nlet startDetectDate = 3d;\n// When the detection window will start (now)\nlet endDetectDate = 0d;\n// When to start collecting data for detection\nlet startDate = startDetectDate + 30d;\n// Operation to monitor, in this case Run Command\nlet monitoredOps = dynamic([\'microsoft.compute/virtualmachines/runcommand/action\']);\n// The resource type to monitor, in this case virtual machines\nlet monitoredResource = pack_array(\'microsoft.compute/virtualmachines\');\nlet pair_probabilities_fl = (tbl:(*), A_col:string, B_col:string, scope_col:string)\n{\nlet T = (tbl | extend _A = column_ifexists(A_col, \'\'), _B = column_ifexists(B_col, \'\'), _scope = column_ifexists(scope_col, \'\'));\nlet countOnScope = T | summarize countAllOnScope = count() by _scope;\nlet probAB = T | summarize countAB = count() by _A, _B, _scope | join kind = leftouter (countOnScope) on _scope | extend P_AB = todouble(countAB)/countAllOnScope;\nlet probA = probAB | summarize countA = sum(countAB), countAllOnScope = max(countAllOnScope) by _A, _scope | extend P_A = todouble(countA)/countAllOnScope;\nlet probB = probAB | summarize countB = sum(countAB), countAllOnScope = max(countAllOnScope) by _B, _scope | extend P_B = todouble(countB)/countAllOnScope;\n probAB\n | join kind = leftouter (probA) on _A, _scope\n | join kind = leftouter (probB) on _B, _scope\n | extend P_AUB = P_A + P_B - P_AB\n , P_AIB = P_AB/P_B\n , P_BIA = P_AB/P_A\n | extend Lift_AB = P_AB/(P_A * P_B)\n , Jaccard_AB = P_AB/P_AUB\n | project _A, _B, _scope, floor(P_A, 0.00001), floor(P_B, 0.00001), floor(P_AB, 0.00001), floor(P_AUB, 0.00001), floor(P_AIB, 0.00001)\n , floor(P_BIA, 0.00001), floor(Lift_AB, 0.00001), floor(Jaccard_AB, 0.00001)\n | sort by _scope, _A, _B\n};\nlet eventsTable = materialize (\nAzureActivity\n| where TimeGenerated between (ago(startDate) .. ago(endDetectDate))\n| where isnotempty(CallerIpAddress)\n| where ActivityStatusValue has_any (\'Success\', \'Succeeded\')\n| extend ResourceId = iff(isempty(_ResourceId), ResourceId, _ResourceId)\n| extend splitOp = split(OperationNameValue, \'/\')\n| extend splitRes = split(ResourceId, \'/\')\n| project TimeGenerated , subscriptionId=SubscriptionId\n , ResourceProvider\n , ResourceName = tolower(tostring(splitRes[-1]))\n , OperationNameValue = tolower(OperationNameValue)\n , timeSlice = floor(TimeGenerated, 1d)\n , clientIp = tostring(CallerIpAddress)\n , Caller\n , isMonitoredOp = iff(OperationNameValue has_any (monitoredOps), 1, 0)\n , isMonitoredResource = iff(OperationNameValue has_any (monitoredResource), 1, 0)\n , CorrelationId\n| extend clientIpMask = format_ipv4_mask(clientIp, 16)\n);\nlet modelData = (\neventsTable\n| where TimeGenerated < ago(startDetectDate) and isnotempty(Caller) and isnotempty(subscriptionId)\n| summarize countEvents = count(), countMonRes = countif(isMonitoredResource == 1), counMonOp = countif(isMonitoredOp == 1)\n , firstSeen = min(timeSlice), firstSeenOnMonRes = minif(timeSlice, isMonitoredResource == 1), firstSeenOnMonOp = minif(timeSlice, isMonitoredOp == 1)\n by subscriptionId, Caller, clientIpMask\n);\nlet monOpProbs = materialize (\neventsTable\n| where TimeGenerated < ago(startDetectDate) and isnotempty(Caller) and isnotempty(subscriptionId)\n| invoke pair_probabilities_fl(\'Caller\', \'isMonitoredResource\',\'subscriptionId\')\n| where _B == 1\n| sort by P_AIB desc\n| extend rankOnMonRes = row_rank(P_AIB), sumBiggerCondProbs = row_cumsum(P_AIB) - P_AIB\n| extend avgBiggerCondProbs = floor(iff(rankOnMonRes > 1, sumBiggerCondProbs/(rankOnMonRes-1), max_of(0.0, prev(sumBiggerCondProbs))), 0.00001)\n| project-away sumBiggerCondProbs\n);\neventsTable\n| where TimeGenerated between (ago(startDetectDate) .. ago(endDetectDate))\n| join kind = leftouter (modelData | summarize countEventsPrincOnSub = sum(countEvents), countEventsMonResPrincOnSub = sum(countMonRes), countEventsMonOpPrincOnSub = sum(counMonOp)\n , firstSeenPrincOnSubs = min(firstSeen), firstSeenMonResPrincOnSubs = min(firstSeenOnMonRes), firstSeenMonOpPrincOnSubs = min(firstSeenOnMonOp) by subscriptionId, Caller) \n on subscriptionId, Caller\n| join kind = leftouter (modelData | summarize countEventsIpMaskOnSub = sum(countEvents), countEventsMonResIpMaskOnSub = sum(countMonRes), countEventsMonOpIpMaskOnSub = sum(counMonOp)\n , firstSeenIpMaskOnSubs = min(firstSeen), firstSeenMonResIpMaskOnSubs = min(firstSeenOnMonRes), firstSeenMonOpIpMaskOnSubs = min(firstSeenOnMonOp) by subscriptionId, clientIpMask) \n on subscriptionId, clientIpMask\n| join kind = leftouter (modelData | summarize countEventsOnSub = sum(countEvents), countEventsMonResOnSub = sum(countMonRes), countEventsMonOpOnSub = sum(counMonOp)\n , firstSeenOnSubs = min(firstSeen), firstSeenMonResOnSubs = min(firstSeenOnMonRes), firstSeenMonOpOnSubs = min(firstSeenOnMonOp)\n , countCallersOnSubs = dcount(Caller), countIpMasksOnSubs = dcount(clientIpMask) by subscriptionId)\n on subscriptionId \n| project-away subscriptionId1, Caller1, subscriptionId2\n| extend daysOnSubs = datetime_diff(\'day\', timeSlice, firstSeenOnSubs)\n| extend avgMonOpOnSubs = floor(1.0*countEventsMonOpOnSub/daysOnSubs, 0.01), avgMonResOnSubs = floor(1.0*countEventsMonResOnSub/daysOnSubs, 0.01)\n| join kind = leftouter(monOpProbs) on $left.subscriptionId == $right._scope, $left.Caller == $right._A\n| project-away _A, _B, _scope\n| sort by subscriptionId asc, TimeGenerated asc\n| extend rnOnSubs = row_number(1, subscriptionId != prev(subscriptionId))\n| sort by subscriptionId asc, Caller asc, TimeGenerated asc\n| extend rnOnCallerSubs = row_number(1, (subscriptionId != prev(subscriptionId) and (Caller != prev(Caller))))\n| extend newCaller = iff(isempty(firstSeenPrincOnSubs), 1, 0)\n , newCallerOnMonRes = iff(isempty(firstSeenMonResPrincOnSubs), 1, 0)\n , newIpMask = iff(isempty(firstSeenIpMaskOnSubs), 1, 0)\n , newIpMaskOnMonRes = iff(isempty(firstSeenMonResIpMaskOnSubs), 1, 0)\n , newMonOpOnSubs = iff(isempty(firstSeenMonResOnSubs), 1, 0)\n , anomCallerMonRes = iff(((Jaccard_AB <= 0.1) or (P_AIB <= 0.1)), 1, 0)\n| project TimeGenerated, subscriptionId, ResourceProvider, ResourceName, OperationNameValue, Caller, CorrelationId, ClientIP=clientIp, ActiveDaysOnSub=daysOnSubs, avgMonOpOnSubs, newCaller, newCallerOnMonRes, newIpMask, newIpMaskOnMonRes, newMonOpOnSubs, anomCallerMonRes, isMonitoredOp, isMonitoredResource\n| order by TimeGenerated\n| where isMonitoredOp == 1\n// Optional - focus only on monitored operations or monitored resource in detection window\n| where isMonitoredOp == 1\n//| where isMonitoredResource == 1\n' + version: 2 + tags: [ + { + name: 'description' + value: 'This query can be used during threat hunts to identify a range of different Azure Operation anomalies.\nThe query is heavily commented inline to explain operation. Anomalies covered are: New Caller, New Caller IP,\nNew Caller IP Range, Anomalous operation based on Jaccard index. By default this query is configured to detect\nanomalous Run Command operations. The operation and resource type to perform anomaly detection can be configured \nat the top of the query along with the detection window parameters' + } + { + name: 'tactics' + value: 'LateralMovement,CredentialAccess' + } + { + name: 'techniques' + value: 'T1570,T1078.004' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId2, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 2' + parentId: huntingQueryId2 + contentId: _huntingQuerycontentId2 + kind: 'HuntingQuery' + version: huntingQueryVersion2 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec3 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName3 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 3 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName3_huntingQueryVersion3 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec3 + name: '${huntingQueryVersion3}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Anomalous_Listing_Of_Storage_Keys_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion3 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_3' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Azure storage key enumeration' + category: 'Hunting Queries' + query: 'AzureActivity\n| where OperationNameValue =~ "microsoft.storage/storageaccounts/listkeys/action"\n| where ActivityStatusValue =~ "Succeeded" \n| join kind= inner (\n AzureActivity\n | where OperationNameValue =~ "microsoft.storage/storageaccounts/listkeys/action"\n | where ActivityStatusValue =~ "Succeeded" \n | project ExpectedIpAddress=CallerIpAddress, Caller \n | evaluate autocluster()\n) on Caller\n| where CallerIpAddress != ExpectedIpAddress\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), ResourceIds = make_set(ResourceId,100), ResourceIdCount = dcount(ResourceId) by OperationNameValue, Caller, CallerIpAddress\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Listing of storage keys is an interesting operation in Azure which might expose additional \nsecrets and PII to callers as well as granting access to VMs. While there are many benign operations of this\ntype, it would be interesting to see if the account performing this activity or the source IP address from \nwhich it is being done is anomalous. \nThe query below generates known clusters of ip address per caller, notice that users which only had single\noperations do not appear in this list as we cannot learn from it their normal activity (only based on a single\nevent). The activities for listing storage account keys is correlated with this learned \nclusters of expected activities and activity which is not expected is returned.' + } + { + name: 'tactics' + value: 'Discovery' + } + { + name: 'techniques' + value: 'T1087' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId3, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 3' + parentId: huntingQueryId3 + contentId: _huntingQuerycontentId3 + kind: 'HuntingQuery' + version: huntingQueryVersion3 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec4 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName4 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 4 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName4_huntingQueryVersion4 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec4 + name: '${huntingQueryVersion4}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'AzureAdministrationFromVPS_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion4 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_4' + location: workspace_location + properties: { + eTag: '*' + displayName: 'AzureActivity Administration From VPS Providers' + category: 'Hunting Queries' + query: 'let IP_Data = (externaldata(network:string)\n[@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/VPS_Networks.csv"] with (format="csv"));\nAzureActivity\n| where CategoryValue =~ "Administrative"\n| evaluate ipv4_lookup(IP_Data, CallerIpAddress, network, return_unmatched = false)\n| summarize Operations = make_set(OperationNameValue), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by CallerIpAddress, Caller\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Looks for administrative actions in AzureActivity from known VPS provider network ranges.\nThis is not an exhaustive list of VPS provider ranges but covers some of the most prevalent providers observed.' + } + { + name: 'tactics' + value: 'InitialAccess' + } + { + name: 'techniques' + value: 'T1078' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId4, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 4' + parentId: huntingQueryId4 + contentId: _huntingQuerycontentId4 + kind: 'HuntingQuery' + version: huntingQueryVersion4 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec5 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName5 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 5 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName5_huntingQueryVersion5 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec5 + name: '${huntingQueryVersion5}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'AzureNSG_AdministrativeOperations_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion5 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_5' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Azure Network Security Group NSG Administrative Operations' + category: 'Hunting Queries' + query: 'let opValues = dynamic(["Microsoft.Network/networkSecurityGroups/write", "Microsoft.Network/networkSecurityGroups/delete"]);\n// Azure NSG Create / Update / Delete\nAzureActivity\n| where Category =~ "Administrative"\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created", "OK","Accepted")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Identifies a set of Azure NSG administrative and operational detection queries for hunting activities.' + } + { + name: 'tactics' + value: 'Impact' + } + { + name: 'techniques' + value: 'T1496' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId5, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 5' + parentId: huntingQueryId5 + contentId: _huntingQuerycontentId5 + kind: 'HuntingQuery' + version: huntingQueryVersion5 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec6 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName6 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 6 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName6_huntingQueryVersion6 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec6 + name: '${huntingQueryVersion6}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'AzureRunCommandFromAzureIP_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion6 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_6' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Azure VM Run Command executed from Azure IP address' + category: 'Hunting Queries' + query: 'let azure_ranges = externaldata(changeNumber: string, cloud: string, values: dynamic)\n["https://raw.githubusercontent.com/microsoft/mstic/master/PublicFeeds/MSFTIPRanges/ServiceTags_Public.json"] with(format=\'multijson\')\n| mv-expand values\n| extend Name = values.name, AddressPrefixes = values.properties.addressPrefixes\n| where Name startswith "WindowsVirtualDesktop"\n| mv-expand AddressPrefixes\n| summarize by tostring(AddressPrefixes);\nAzureActivity\n| where TimeGenerated > ago(30d)\n// Isolate run command actions\n| where OperationNameValue == "Microsoft.Compute/virtualMachines/runCommand/action"\n// Confirm that the operation impacted a virtual machine\n| where Authorization has "virtualMachines"\n// Each runcommand operation consists of three events when successful, Started, Accepted (or Rejected), Successful (or Failed).\n| summarize StartTime=min(TimeGenerated), EndTime=max(TimeGenerated), max(CallerIpAddress), make_list(ActivityStatusValue) by CorrelationId, Authorization, Caller\n// Limit to Run Command executions that Succeeded\n| where list_ActivityStatusValue has "Succeeded"\n// Extract data from the Authorization field, allowing us to later extract the Caller (UPN) and CallerIpAddress\n| extend Authorization_d = parse_json(Authorization)\n| extend Scope = Authorization_d.scope\n| extend Scope_s = split(Scope, "/")\n| extend Subscription = tostring(Scope_s[2])\n| extend VirtualMachineName = tostring(Scope_s[-1])\n| project StartTime, EndTime, Subscription, VirtualMachineName, CorrelationId, Caller, CallerIpAddress=max_CallerIpAddress\n| evaluate ipv4_lookup(azure_ranges, CallerIpAddress, AddressPrefixes)\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Identifies any Azure VM Run Command operation executed from an Azure IP address.\nRun Command allows an attacker or legitimate user to execute arbitrary PowerShell\non a target VM. This technique has been seen in use by NOBELIUM.' + } + { + name: 'tactics' + value: 'LateralMovement,CredentialAccess' + } + { + name: 'techniques' + value: 'T1570,T1078.004' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId6, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 6' + parentId: huntingQueryId6 + contentId: _huntingQuerycontentId6 + kind: 'HuntingQuery' + version: huntingQueryVersion6 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec7 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName7 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 7 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName7_huntingQueryVersion7 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec7 + name: '${huntingQueryVersion7}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'AzureSentinelConnectors_AdministrativeOperations_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion7 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_7' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Microsoft Sentinel Connectors Administrative Operations' + category: 'Hunting Queries' + query: 'let opValues = dynamic(["Microsoft.SecurityInsights/dataConnectors/write", "Microsoft.SecurityInsights/dataConnectors/delete"]);\n// Microsoft Sentinel Data Connectors Update / Delete\nAzureActivity\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created", "OK")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Identifies a set of Microsoft Sentinel Data Connectors for administrative and operational detection queries for hunting activities.' + } + { + name: 'tactics' + value: 'Impact' + } + { + name: 'techniques' + value: 'T1496' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId7, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 7' + parentId: huntingQueryId7 + contentId: _huntingQuerycontentId7 + kind: 'HuntingQuery' + version: huntingQueryVersion7 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec8 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName8 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 8 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName8_huntingQueryVersion8 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec8 + name: '${huntingQueryVersion8}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'AzureSentinelWorkbooks_AdministrativeOperation_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion8 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_8' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Microsoft Sentinel Workbooks Administrative Operations' + category: 'Hunting Queries' + query: 'let opValues = dynamic(["microsoft.insights/workbooks/write", "microsoft.insights/workbooks/delete"]);\n// Microsoft Sentinel Workbook Create / Update / Delete\nAzureActivity\n| where Category =~ "Administrative"\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created", "OK")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Identifies set of Microsoft Sentinel Workbooks administrative operational detection queries for hunting activites' + } + { + name: 'tactics' + value: 'Impact' + } + { + name: 'techniques' + value: 'T1496' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId8, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 8' + parentId: huntingQueryId8 + contentId: _huntingQuerycontentId8 + kind: 'HuntingQuery' + version: huntingQueryVersion8 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec9 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName9 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 9 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName9_huntingQueryVersion9 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec9 + name: '${huntingQueryVersion9}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'AzureVirtualNetworkSubnets_AdministrativeOperationset_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion9 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_9' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Azure Virtual Network Subnets Administrative Operations' + category: 'Hunting Queries' + query: 'let opValues = dynamic(["Microsoft.Network/virtualNetworks/subnets/write","Microsoft.Network/virtualNetworks/subnets/delete"]);\n// Creating, Updating or Deleting Virtual Network Subnets\nAzureActivity\n| where CategoryValue =~ "Administrative"\n| where OperationNameValue in~ (opValues)\n| where ActivitySubstatusValue in~ ("Created","Accepted")\n| sort by TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Identifies a set of Azure Virtual Network Subnets for administrative and operational detection queries for hunting activities.' + } + { + name: 'tactics' + value: 'Impact' + } + { + name: 'techniques' + value: 'T1496' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId9, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 9' + parentId: huntingQueryId9 + contentId: _huntingQuerycontentId9 + kind: 'HuntingQuery' + version: huntingQueryVersion9 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec10 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName10 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 10 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName10_huntingQueryVersion10 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec10 + name: '${huntingQueryVersion10}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Common_Deployed_Resources_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion10 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_10' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Common deployed resources' + category: 'Hunting Queries' + query: 'AzureActivity\n| where OperationNameValue has_any (@"deployments/write", @"virtualMachines/write") \n| where ActivityStatusValue =~ "Succeeded"\n| summarize by bin(TimeGenerated,1d), Resource, ResourceGroup, ResourceId, OperationNameValue, Caller\n| evaluate basket()\n| where isnotempty(Caller) and isnotempty(Resource) and isnotempty(TimeGenerated)\n| order by Percent desc, TimeGenerated desc\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend AzureResource_0_ResourceId = ResourceId\n// remove comments below on filters if the goal is to see more common or more rare Resource, Resource Group and Caller combinations\n//| where Percent <= 40 // <-- more rare\n//| where Percent >= 60 // <-- more common\n' + version: 2 + tags: [ + { + name: 'description' + value: 'This query looks for common deployed resources (resource name and resource groups) and can be used\nin combination with other signals that show suspicious deployment to evaluate if the resource is one\nthat is commonly being deployed/created or unique.\nTo understand the basket() function better see - https://docs.microsoft.com/azure/data-explorer/kusto/query/basketplugin' + } + { + name: 'tactics' + value: 'Impact' + } + { + name: 'techniques' + value: 'T1496' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId10, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 10' + parentId: huntingQueryId10 + contentId: _huntingQuerycontentId10 + kind: 'HuntingQuery' + version: huntingQueryVersion10 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec11 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName11 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 11 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName11_huntingQueryVersion11 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec11 + name: '${huntingQueryVersion11}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Creating_Anomalous_Number_Of_Resources_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion11 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_11' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Creation of an anomalous number of resources' + category: 'Hunting Queries' + query: 'AzureActivity\n| where OperationNameValue in~ ("microsoft.compute/virtualMachines/write", "microsoft.resources/deployments/write")\n| where ActivityStatusValue == "Succeeded" \n| make-series dcount(ResourceId) default=0 on EventSubmissionTimestamp in range(ago(7d), now(), 1d) by Caller\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Looks for anomalous number of resources creation or deployment activities in azure activity log.\nIt is best to run this query on a look back period which is at least 7 days.' + } + { + name: 'tactics' + value: 'Impact' + } + { + name: 'techniques' + value: 'T1496' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId11, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 11' + parentId: huntingQueryId11 + contentId: _huntingQuerycontentId11 + kind: 'HuntingQuery' + version: huntingQueryVersion11 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec12 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName12 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 12 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName12_huntingQueryVersion12 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec12 + name: '${huntingQueryVersion12}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Granting_Permissions_to_Account_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion12 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_12' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Granting permissions to account' + category: 'Hunting Queries' + query: 'AzureActivity\n| where OperationName =~ "Create role assignment"\n| where ActivityStatus =~ "Succeeded" \n| project Caller, CallerIpAddress\n| evaluate basket()\n// Returns all the records from the left side and only matching records from the right side.\n| join kind=leftouter (AzureActivity\n| where OperationName =~ "Create role assignment"\n| where ActivityStatus =~ "Succeeded"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by Caller, CallerIpAddress)\non Caller, CallerIpAddress\n| project-away Caller1, CallerIpAddress1\n| where isnotempty(StartTime)\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Shows the most prevalent users who grant access to others on Azure resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.' + } + { + name: 'tactics' + value: 'Persistence,PrivilegeEscalation' + } + { + name: 'techniques' + value: 'T1098' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId12, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 12' + parentId: huntingQueryId12 + contentId: _huntingQuerycontentId12 + kind: 'HuntingQuery' + version: huntingQueryVersion12 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec13 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName13 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 13 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName13_huntingQueryVersion13 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec13 + name: '${huntingQueryVersion13}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'PortOpenedForAzureResource_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion13 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_13' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Port opened for an Azure Resource' + category: 'Hunting Queries' + query: 'let lookback = 7d;\nAzureActivity\n| where TimeGenerated >= ago(lookback)\n| where OperationNameValue has_any ("ipfilterrules", "securityRules", "publicIPAddresses", "firewallrules") and OperationNameValue endswith "write"\n// Choosing Accepted here because it has the Rule Attributes included\n| where ActivityStatusValue == "Accepted" \n// If there is publicIP info, include it\n| extend parsed_properties = parse_json(tostring(parse_json(Properties).responseBody)).properties\n| extend publicIPAddressVersion = case(Properties has_cs \'publicIPAddressVersion\',tostring(parsed_properties.publicIPAddressVersion),"")\n| extend publicIPAllocationMethod = case(Properties has_cs \'publicIPAllocationMethod\',tostring(parsed_properties.publicIPAllocationMethod),"")\n// Include rule attributes for context\n| extend access = case(Properties has_cs \'access\',tostring(parsed_properties.access),"")\n| extend description = case(Properties has_cs \'description\',tostring(parsed_properties.description),"")\n| extend destinationPortRange = case(Properties has_cs \'destinationPortRange\',tostring(parsed_properties.destinationPortRange),"")\n| extend direction = case(Properties has_cs \'direction\',tostring(parsed_properties.direction),"")\n| extend protocol = case(Properties has_cs \'protocol\',tostring(parsed_properties.protocol),"")\n| extend sourcePortRange = case(Properties has_cs \'sourcePortRange\',tostring(parsed_properties.sourcePortRange),"")\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), ResourceIds = make_set(_ResourceId,100) by Caller, CallerIpAddress, Resource, ResourceGroup, \nActivityStatusValue, ActivitySubstatus, SubscriptionId, access, description, destinationPortRange, direction, protocol, sourcePortRange, publicIPAddressVersion, publicIPAllocationMethod\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'Identifies what ports may have been opened for a given Azure Resource over the last 7 days' + } + { + name: 'tactics' + value: 'CommandAndControl,Impact' + } + { + name: 'techniques' + value: 'T1071,T1571,T1496' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId13, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 13' + parentId: huntingQueryId13 + contentId: _huntingQuerycontentId13 + kind: 'HuntingQuery' + version: huntingQueryVersion13 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource huntingQueryTemplateSpec14 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: huntingQueryTemplateSpecName14 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Azure Activity Hunting Query 14 with template' + displayName: 'Azure Activity Hunting Query template' + } +} + +resource huntingQueryTemplateSpecName14_huntingQueryVersion14 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: huntingQueryTemplateSpec14 + name: '${huntingQueryVersion14}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'HuntingQuery' + } + properties: { + description: 'Rare_Custom_Script_Extension_HuntingQueries Hunting Query with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: huntingQueryVersion14 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.OperationalInsights/savedSearches' + apiVersion: '2020-08-01' + name: 'Azure_Activity_Hunting_Query_14' + location: workspace_location + properties: { + eTag: '*' + displayName: 'Rare Custom Script Extension' + category: 'Hunting Queries' + query: 'let starttime = todatetime(\'{{StartTimeISO}}\');\nlet endtime = todatetime(\'{{EndTimeISO}}\');\nlet Lookback = starttime - 14d;\nlet CustomScriptExecution = AzureActivity\n| where TimeGenerated >= Lookback\n| where OperationName =~ "Create or Update Virtual Machine Extension"\n| extend parsed_properties = parse_json(Properties)\n| extend Settings = tostring((parse_json(tostring(parsed_properties.responseBody)).properties).settings)\n| parse Settings with * \'fileUris":[\' FileURI "]" *\n| parse Settings with * \'commandToExecute":\' commandToExecute \'}\' *\n| extend message_ = tostring((parse_json(tostring(parsed_properties.statusMessage)).error).message);\nlet LookbackCustomScriptExecution = CustomScriptExecution\n| where TimeGenerated >= Lookback and TimeGenerated < starttime\n| where isnotempty(FileURI) and isnotempty(commandToExecute)\n| summarize max(TimeGenerated), OperationCount = count() by Caller, Resource, CallerIpAddress, FileURI, commandToExecute;\nlet CurrentCustomScriptExecution = CustomScriptExecution\n| where TimeGenerated between (starttime..endtime)\n| where isnotempty(FileURI) and isnotempty(commandToExecute)\n| project TimeGenerated, ActivityStatus, OperationId, CorrelationId, ResourceId, CallerIpAddress, Caller, OperationName, Resource, ResourceGroup, FileURI, commandToExecute, FailureMessage = message_, HTTPRequest, Settings;\nlet RareCustomScriptExecution = CurrentCustomScriptExecution\n| join kind= leftanti (LookbackCustomScriptExecution) on Caller, CallerIpAddress, FileURI, commandToExecute;\nlet IPCheck = RareCustomScriptExecution\n| summarize arg_max(TimeGenerated, OperationName), OperationIds = make_set(OperationId,100), CallerIpAddresses = make_set(CallerIpAddress,100) by ActivityStatus, CorrelationId, ResourceId, Caller, Resource, ResourceGroup, FileURI, commandToExecute, FailureMessage\n| extend IPArray = array_length(CallerIpAddresses);\n//Get IPs for later summarization so all associated CorrelationIds and Caller actions have an IP. Success and Fails do not always have IP\nlet multiIP = IPCheck | where IPArray > 1\n| mv-expand CallerIpAddresses | extend CallerIpAddress = tostring(CallerIpAddresses)\n| where isnotempty(CallerIpAddresses);\nlet singleIP = IPCheck | where IPArray <= 1\n| mv-expand CallerIpAddresses | extend CallerIpAddress = tostring(CallerIpAddresses);\nlet FullDetails = singleIP | union multiIP;\n//Get IP address associated with successes and fails with no IP listed\nlet IPList = FullDetails | where isnotempty(CallerIpAddress) | summarize by CorrelationId, Caller, CallerIpAddress;\nlet EmptyIP = FullDetails | where isempty(CallerIpAddress) | project-away CallerIpAddress;\nlet IpJoin = EmptyIP | join kind= leftouter (IPList) on CorrelationId, Caller | project-away CorrelationId1, Caller1;\nlet nonEmptyIP = FullDetails | where isnotempty(CallerIpAddress);\nnonEmptyIP | union IpJoin\n// summarize all activities with a given CorrelationId and Caller together so we can provide a singular result\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), ActivityStatusSet = make_set(ActivityStatus,100), OperationIds = make_set(OperationIds,100), FailureMessages = make_set(FailureMessage,100) by CorrelationId, ResourceId, CallerIpAddress, Caller, Resource, ResourceGroup, FileURI, commandToExecute\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| extend Account_0_Name = Name\n| extend Account_0_UPNSuffix = UPNSuffix\n| extend IP_0_Address = CallerIpAddress\n' + version: 2 + tags: [ + { + name: 'description' + value: 'The Custom Script Extension downloads and executes scripts on Azure virtual machines. This extension is useful for post deployment configuration, software installation, or any other configuration or management tasks.\n Scripts could be downloaded from external links, Azure storage, GitHub, or provided to the Azure portal at extension run time. This could also be used maliciously by an attacker.\n The query tries to identify rare custom script extensions that have been executed in your environment' + } + { + name: 'tactics' + value: 'Execution' + } + { + name: 'techniques' + value: 'T1059' + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/HuntingQuery-${last(split(huntingQueryId14, '/'))}' + properties: { + description: 'Azure Activity Hunting Query 14' + parentId: huntingQueryId14 + contentId: _huntingQuerycontentId14 + kind: 'HuntingQuery' + version: huntingQueryVersion14 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec1 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName1 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 1 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName1_analyticRuleVersion1 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec1 + name: '${analyticRuleVersion1}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'AADHybridHealthADFSNewServer_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion1 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId1 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Azure AD Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/' + displayName: 'Azure Active Directory Hybrid Health AD FS New Server' + enabled: false + query: 'AzureActivity\n| where CategoryValue =~ \'Administrative\'\n| where ResourceProviderValue =~ \'Microsoft.ADHybridHealthService\'\n| where _ResourceId has \'AdFederationService\'\n| where OperationNameValue =~ \'Microsoft.ADHybridHealthService/services/servicemembers/action\'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| project-away claimsJson\n' + queryFrequency: 'P1D' + queryPeriod: 'P1D' + severity: 'Medium' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'DefenseEvasion' + ] + techniques: [ + 'T1578' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId1, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 1' + parentId: analyticRuleId1 + contentId: _analyticRulecontentId1 + kind: 'AnalyticsRule' + version: analyticRuleVersion1 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec2 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName2 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 2 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName2_analyticRuleVersion2 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec2 + name: '${analyticRuleVersion2}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'AADHybridHealthADFSServiceDelete_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion2 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId2 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'This detection uses AzureActivity logs (Administrative category) to identify the deletion of an Azure AD Hybrid Health AD FS service instance in a tenant.\nA threat actor can create a new AD Health ADFS service and create a fake server to spoof AD FS signing logs.\nThe health AD FS service can then be deleted after it is no longer needed via HTTP requests to Azure.\nMore information is available in this blog https://o365blog.com/post/hybridhealthagent/' + displayName: 'Azure Active Directory Hybrid Health AD FS Service Delete' + enabled: false + query: 'AzureActivity\n| where CategoryValue =~ \'Administrative\'\n| where ResourceProviderValue =~ \'Microsoft.ADHybridHealthService\'\n| where _ResourceId has \'AdFederationService\'\n| where OperationNameValue =~ \'Microsoft.ADHybridHealthService/services/delete\'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| project-away claimsJson\n' + queryFrequency: 'P1D' + queryPeriod: 'P1D' + severity: 'Medium' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'DefenseEvasion' + ] + techniques: [ + 'T1578' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId2, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 2' + parentId: analyticRuleId2 + contentId: _analyticRulecontentId2 + kind: 'AnalyticsRule' + version: analyticRuleVersion2 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec3 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName3 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 3 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName3_analyticRuleVersion3 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec3 + name: '${analyticRuleVersion3}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'AADHybridHealthADFSSuspApp_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion3 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId3 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'This detection uses AzureActivity logs (Administrative category) to identify a suspicious application adding a server instance to an Azure AD Hybrid Health AD FS service or deleting the AD FS service instance.\nUsually the Azure AD Connect Health Agent application with ID cf6d7e68-f018-4e0a-a7b3-126e053fb88d and ID cb1056e2-e479-49de-ae31-7812af012ed8 is used to perform those operations.' + displayName: 'Azure Active Directory Hybrid Health AD FS Suspicious Application' + enabled: false + query: '// Azure AD Connect Health Agent - cf6d7e68-f018-4e0a-a7b3-126e053fb88d\n// Azure Active Directory Connect - cb1056e2-e479-49de-ae31-7812af012ed8\nlet appList = dynamic([\'cf6d7e68-f018-4e0a-a7b3-126e053fb88d\',\'cb1056e2-e479-49de-ae31-7812af012ed8\']);\nlet operationNamesList = dynamic([\'Microsoft.ADHybridHealthService/services/servicemembers/action\',\'Microsoft.ADHybridHealthService/services/delete\']);\nAzureActivity\n| where CategoryValue =~ \'Administrative\'\n| where ResourceProviderValue =~ \'Microsoft.ADHybridHealthService\'\n| where _ResourceId has \'AdFederationService\'\n| where OperationNameValue in~ (operationNamesList)\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| where AppId !in (appList)\n| project-away claimsJson\n' + queryFrequency: 'P1D' + queryPeriod: 'P1D' + severity: 'Medium' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'CredentialAccess' + 'DefenseEvasion' + ] + techniques: [ + 'T1528' + 'T1550' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId3, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 3' + parentId: analyticRuleId3 + contentId: _analyticRulecontentId3 + kind: 'AnalyticsRule' + version: analyticRuleVersion3 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec4 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName4 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 4 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName4_analyticRuleVersion4 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec4 + name: '${analyticRuleVersion4}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Creating_Anomalous_Number_Of_Resources_detection_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion4 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId4 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'Indicates when an anomalous number of VM creations or deployment activities occur in Azure via the AzureActivity log. This query generates the baseline pattern of cloud resource creation by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.' + displayName: 'Suspicious number of resource creation or deployment activities' + enabled: false + query: 'let szOperationNames = dynamic(["microsoft.compute/virtualMachines/write", "microsoft.resources/deployments/write"]);\nlet starttime = 7d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TimeSeriesData =\nAzureActivity\n| where TimeGenerated between (startofday(ago(starttime)) .. startofday(now()))\n| where OperationNameValue in~ (szOperationNames)\n| project TimeGenerated, Caller \n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller; \nTimeSeriesData\n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, \'linefit\')\n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long) \n| where TimeGenerated >= startofday(ago(endtime))\n| where anomalies > 0 and baseline > 0\n| project Caller, TimeGenerated, Total, baseline, anomalies, score\n| join (AzureActivity\n| where TimeGenerated > startofday(ago(endtime)) \n| where OperationNameValue in~ (szOperationNames)\n| summarize make_set(OperationNameValue,100), make_set(_ResourceId,100), make_set(CallerIpAddress,100) by bin(TimeGenerated, timeframe), Caller\n) on TimeGenerated, Caller\n| mv-expand CallerIpAddress=set_CallerIpAddress\n| project-away Caller1\n| extend Name = iif(Caller has \'@\',tostring(split(Caller,\'@\',0)[0]),"")\n| extend UPNSuffix = iif(Caller has \'@\',tostring(split(Caller,\'@\',1)[0]),"")\n| extend AadUserId = iif(Caller !has \'@\',Caller,"")\n' + queryFrequency: 'P1D' + queryPeriod: 'P7D' + severity: 'Medium' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'Impact' + ] + techniques: [ + 'T1496' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + { + columnName: 'AadUserId' + identifier: 'AadUserId' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId4, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 4' + parentId: analyticRuleId4 + contentId: _analyticRulecontentId4 + kind: 'AnalyticsRule' + version: analyticRuleVersion4 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec5 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName5 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 5 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName5_analyticRuleVersion5 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec5 + name: '${analyticRuleVersion5}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Creation_of_Expensive_Computes_in_Azure_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion5 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId5 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions' + displayName: 'Creation of expensive computes in Azure' + enabled: false + query: 'let tokens = dynamic(["416","208","192","128","120","96","80","72","64","48","44","40","g5","gs5","g4","gs4","nc12","nc24","nv24"]);\nlet operationList = dynamic(["microsoft.compute/virtualmachines/write", "microsoft.resources/deployments/write"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith "Accept"\n| where Properties has \'vmSize\'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| where vmSize has_any (tokens)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' + queryFrequency: 'P1D' + queryPeriod: 'P1D' + severity: 'Low' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 1 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'DefenseEvasion' + ] + techniques: [ + 'T1578' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId5, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 5' + parentId: analyticRuleId5 + contentId: _analyticRulecontentId5 + kind: 'AnalyticsRule' + version: analyticRuleVersion5 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec6 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName6 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 6 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName6_analyticRuleVersion6 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec6 + name: '${analyticRuleVersion6}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Granting_Permissions_To_Account_detection_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion6 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId6 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'Identifies IPs from which users grant access to other users on Azure resources and alerts when a previously unseen source IP address is used.' + displayName: 'Suspicious granting of permissions to an account' + enabled: false + query: 'let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\nlet AzureBuiltInRole = externaldata(Role:string,RoleDescription:string,ID:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/AzureBuiltInRole.csv"] with (format="csv", ignoreFirstRecord=True);\nlet createRoleAssignmentActivity = AzureActivity\n| where OperationNameValue =~ "microsoft.authorization/roleassignments/write";\nlet RoleAssignedActivity = createRoleAssignmentActivity \n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, bin(TimeGenerated, 1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don\'t have matches from the left.\n| join kind = rightanti ( \ncreateRoleAssignmentActivity\n| where TimeGenerated > ago(endtime)\n| extend parsed_property = tostring(parse_json(Properties).requestbody)\n| extend PrincipalId = case(parsed_property has_cs \'PrincipalId\',parse_json(parsed_property).Properties.PrincipalId, parsed_property has_cs \'principalId\',parse_json(parsed_property).properties.principalId,"")\n| extend PrincipalType = case(parsed_property has_cs \'PrincipalType\',parse_json(parsed_property).Properties.PrincipalType, parsed_property has_cs \'principalType\',parse_json(parsed_property).properties.principalType, "")\n| extend Scope = case(parsed_property has_cs \'Scope\',parse_json(parsed_property).Properties.Scope, parsed_property has_cs \'scope\',parse_json(parsed_property).properties.scope,"")\n| extend RoleAddedDetails = case(parsed_property has_cs \'RoleDefinitionId\',parse_json(parsed_property).Properties.RoleDefinitionId,parsed_property has_cs \'roleDefinitionId\',parse_json(parsed_property).properties.roleDefinitionId,"")\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated), ActivityStatusValue = make_set(ActivityStatusValue), CorrelationId = make_set(CorrelationId), ActivityCountByCallerIPAddress = count() \nby ResourceId, CallerIpAddress, Caller, OperationNameValue, Resource, ResourceGroup, PrincipalId, PrincipalType, Scope, RoleAddedDetails\n) on CallerIpAddress, Caller\n| extend timestamp = StartTimeUtc, AccountCustomEntity = Caller, IPCustomEntity = CallerIpAddress;\nlet RoleAssignedActivitywithRoleDetails = RoleAssignedActivity\n| extend RoleAssignedID = tostring(split(RoleAddedDetails, "/")[-1])\n// Returns all matching records from left and right sides.\n| join kind = inner (AzureBuiltInRole \n) on $left.RoleAssignedID == $right.ID;\nlet CallerIPCountSummary = RoleAssignedActivitywithRoleDetails | summarize AssignmentCountbyCaller = count() by Caller, CallerIpAddress;\nlet RoleAssignedActivityWithCount = RoleAssignedActivitywithRoleDetails | join kind = inner (CallerIPCountSummary | project Caller, AssignmentCountbyCaller, CallerIpAddress) on Caller, CallerIpAddress;\nRoleAssignedActivityWithCount\n| summarize arg_max(StartTimeUtc, *) by PrincipalId, RoleAssignedID\n// \tReturns all the records from the left side and only matching records from the right side.\n| join kind = leftouter( IdentityInfo\n| summarize arg_max(TimeGenerated, *) by AccountObjectId\n) on $left.PrincipalId == $right.AccountObjectId\n// Check if assignment count is greater than the threshold.\n| where AssignmentCountbyCaller >= alertOperationThreshold\n| project ActivityTimeStamp, OperationNameValue, Caller, CallerIpAddress, PrincipalId, RoleAssignedID, RoleAddedDetails, Role, RoleDescription, AccountUPN, AccountCreationTime, GroupMembership, UserType, ActivityStatusValue, ResourceGroup, PrincipalType, Scope, CorrelationId, timestamp, AccountCustomEntity, IPCustomEntity, AssignmentCountbyCaller\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' + queryFrequency: 'P1D' + queryPeriod: 'P14D' + severity: 'Medium' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + { + dataTypes: [ + 'IdentityInfo' + ] + connectorId: 'BehaviorAnalytics' + } + ] + tactics: [ + 'Persistence' + 'PrivilegeEscalation' + ] + techniques: [ + 'T1098' + 'T1548' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId6, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 6' + parentId: analyticRuleId6 + contentId: _analyticRulecontentId6 + kind: 'AnalyticsRule' + version: analyticRuleVersion6 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec7 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName7 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 7 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName7_analyticRuleVersion7 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec7 + name: '${analyticRuleVersion7}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'NRT-AADHybridHealthADFSNewServer_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion7 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId7 + apiVersion: '2022-04-01-preview' + kind: 'NRT' + location: workspace_location + properties: { + description: 'This detection uses AzureActivity logs (Administrative category) to identify the creation or update of a server instance in an Azure AD Hybrid Health AD FS service.\nA threat actor can create a new AD Health ADFS service and create a fake server instance to spoof AD FS signing logs. There is no need to compromise an on-premises AD FS server.\nThis can be done programmatically via HTTP requests to Azure. More information in this blog: https://o365blog.com/post/hybridhealthagent/' + displayName: 'NRT Azure Active Directory Hybrid Health AD FS New Server' + enabled: false + query: 'AzureActivity\n| where CategoryValue =~ \'Administrative\'\n| where ResourceProviderValue =~ \'Microsoft.ADHybridHealthService\'\n| where _ResourceId has \'AdFederationService\'\n| where OperationNameValue =~ \'Microsoft.ADHybridHealthService/services/servicemembers/action\'\n| extend claimsJson = parse_json(Claims)\n| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n| project-away claimsJson\n' + severity: 'Medium' + suppressionDuration: 'PT1H' + suppressionEnabled: false + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'DefenseEvasion' + ] + techniques: [ + 'T1578' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId7, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 7' + parentId: analyticRuleId7 + contentId: _analyticRulecontentId7 + kind: 'AnalyticsRule' + version: analyticRuleVersion7 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec8 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName8 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 8 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName8_analyticRuleVersion8 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec8 + name: '${analyticRuleVersion8}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'NRT_Creation_of_Expensive_Computes_in_Azure_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion8 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId8 + apiVersion: '2022-04-01-preview' + kind: 'NRT' + location: workspace_location + properties: { + description: 'Identifies the creation of large size or expensive VMs (with GPUs or with a large number of virtual CPUs) in Azure.\nAn adversary may create new or update existing virtual machines to evade defenses or use them for cryptomining purposes.\nFor Windows/Linux Vm Sizes, see https://docs.microsoft.com/azure/virtual-machines/windows/sizes \nAzure VM Naming Conventions, see https://docs.microsoft.com/azure/virtual-machines/vm-naming-conventions' + displayName: 'NRT Creation of expensive computes in Azure' + enabled: false + query: 'let tokens = dynamic(["416","208","192","128","120","96","80","72","64","48","44","40","g5","gs5","g4","gs4","nc12","nc24","nv24"]);\nlet operationList = dynamic(["microsoft.compute/virtualmachines/write", "microsoft.resources/deployments/write"]);\nAzureActivity\n| where OperationNameValue in~ (operationList)\n| where ActivityStatusValue startswith "Accept"\n| where Properties has \'vmSize\'\n| extend parsed_property= parse_json(tostring((parse_json(Properties).responseBody))).properties\n| extend vmSize = tostring((parsed_property.hardwareProfile).vmSize)\n| where vmSize has_any (tokens)\n| extend ComputerName = tostring((parsed_property.osProfile).computerName)\n| project TimeGenerated, OperationNameValue, ActivityStatusValue, Caller, CallerIpAddress, ComputerName, vmSize\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' + severity: 'Medium' + suppressionDuration: 'PT1H' + suppressionEnabled: false + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'DefenseEvasion' + ] + techniques: [ + 'T1578' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId8, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 8' + parentId: analyticRuleId8 + contentId: _analyticRulecontentId8 + kind: 'AnalyticsRule' + version: analyticRuleVersion8 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec9 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName9 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 9 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName9_analyticRuleVersion9 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec9 + name: '${analyticRuleVersion9}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'New-CloudShell-User_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion9 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId9 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'Identifies when a user creates an Azure CloudShell for the first time.\nMonitor this activity to ensure only the expected users are using CloudShell.' + displayName: 'New CloudShell User' + enabled: false + query: 'let match_window = 3m;\nAzureActivity\n| where ResourceGroup has "cloud-shell"\n| where (OperationNameValue =~ "Microsoft.Storage/storageAccounts/listKeys/action")\n| where ActivityStatusValue =~ "Success"\n| extend TimeKey = bin(TimeGenerated, match_window), AzureIP = CallerIpAddress\n| join kind = inner\n(AzureActivity\n| where ResourceGroup has "cloud-shell"\n| where (OperationNameValue =~ "Microsoft.Storage/storageAccounts/write")\n| extend TimeKey = bin(TimeGenerated, match_window), UserIP = CallerIpAddress\n) on Caller, TimeKey\n| summarize count() by TimeKey, Caller, ResourceGroup, SubscriptionId, TenantId, AzureIP, UserIP, HTTPRequest, Type, Properties, CategoryValue, OperationList = strcat(OperationNameValue, \' , \', OperationNameValue1)\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' + queryFrequency: 'P1D' + queryPeriod: 'P1D' + severity: 'Low' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'Execution' + ] + techniques: [ + 'T1059' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'UserIP' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId9, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 9' + parentId: analyticRuleId9 + contentId: _analyticRulecontentId9 + kind: 'AnalyticsRule' + version: analyticRuleVersion9 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec10 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName10 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 10 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName10_analyticRuleVersion10 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec10 + name: '${analyticRuleVersion10}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'NewResourceGroupsDeployedTo_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion10 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId10 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'Identifies when a rare Resource and ResourceGroup deployment occurs by a previously unseen caller.' + displayName: 'Suspicious Resource deployment' + enabled: false + query: '// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet szOperationNames = dynamic(["Microsoft.Compute/virtualMachines/write", "Microsoft.Resources/deployments/write", "Microsoft.Resources/subscriptions/resourceGroups/write"]);\nlet starttime = 14d;\nlet endtime = 1d;\nlet RareCaller = AzureActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n// Returns all the records from the right side that don\'t have matches from the left.\n| join kind=rightantisemi (\nAzureActivity\n| where TimeGenerated > ago(endtime)\n| where OperationNameValue in~ (szOperationNames)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_set(TimeGenerated,100), ActivityStatusValue = make_set(ActivityStatusValue,100), CorrelationIds = make_set(CorrelationId,100), ResourceGroups = make_set(ResourceGroup,100), ResourceIds = make_set(_ResourceId,100), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue) on CallerIpAddress, Caller, OperationNameValue;\nRareCaller\n| extend Name = iif(Caller has \'@\',tostring(split(Caller,\'@\',0)[0]),"")\n| extend UPNSuffix = iif(Caller has \'@\',tostring(split(Caller,\'@\',1)[0]),"")\n| extend AadUserId = iif(Caller !has \'@\',Caller,"")\n' + queryFrequency: 'P1D' + queryPeriod: 'P14D' + severity: 'Low' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'Impact' + ] + techniques: [ + 'T1496' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + { + columnName: 'AadUserId' + identifier: 'AadUserId' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId10, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 10' + parentId: analyticRuleId10 + contentId: _analyticRulecontentId10 + kind: 'AnalyticsRule' + version: analyticRuleVersion10 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec11 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName11 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 11 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName11_analyticRuleVersion11 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec11 + name: '${analyticRuleVersion11}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'RareOperations_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion11 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId11 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'This query looks for a few sensitive subscription-level events based on Azure Activity Logs. For example, this monitors for the operation name \'Create or Update Snapshot\', which is used for creating backups but could be misused by attackers to dump hashes or extract sensitive information from the disk.' + displayName: 'Rare subscription-level operations in Azure' + enabled: false + query: 'let starttime = 14d;\nlet endtime = 1d;\n// The number of operations above which an IP address is considered an unusual source of role assignment operations\nlet alertOperationThreshold = 5;\n// Add or remove operation names below as per your requirements. For operations lists, please refer to https://learn.microsoft.com/en-us/Azure/role-based-access-control/resource-provider-operations#all\nlet SensitiveOperationList = dynamic(["microsoft.compute/snapshots/write", "microsoft.network/networksecuritygroups/write", "microsoft.storage/storageaccounts/listkeys/action"]);\nlet SensitiveActivity = AzureActivity\n| where OperationNameValue in~ (SensitiveOperationList) or OperationNameValue hassuffix "listkeys/action"\n| where ActivityStatusValue =~ "Success";\nSensitiveActivity\n| where TimeGenerated between (ago(starttime) .. ago(endtime))\n| summarize count() by CallerIpAddress, Caller, OperationNameValue, bin(TimeGenerated,1d)\n| where count_ >= alertOperationThreshold\n// Returns all the records from the right side that don\'t have matches from the left\n| join kind = rightanti (\nSensitiveActivity\n| where TimeGenerated >= ago(endtime)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = make_list(TimeGenerated), ActivityStatusValue = make_list(ActivityStatusValue), CorrelationIds = make_list(CorrelationId), ResourceGroups = make_list(ResourceGroup), ResourceIds = make_list(_ResourceId), ActivityCountByCallerIPAddress = count()\nby CallerIpAddress, Caller, OperationNameValue\n| where ActivityCountByCallerIPAddress >= alertOperationThreshold\n) on CallerIpAddress, Caller, OperationNameValue\n| extend Name = tostring(split(Caller,\'@\',0)[0]), UPNSuffix = tostring(split(Caller,\'@\',1)[0])\n' + queryFrequency: 'P1D' + queryPeriod: 'P14D' + severity: 'Low' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'CredentialAccess' + 'Persistence' + ] + techniques: [ + 'T1003' + 'T1098' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + ] + } + { + entityType: 'IP' + fieldMappings: [ + { + columnName: 'CallerIpAddress' + identifier: 'Address' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId11, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 11' + parentId: analyticRuleId11 + contentId: _analyticRulecontentId11 + kind: 'AnalyticsRule' + version: analyticRuleVersion11 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource analyticRuleTemplateSpec12 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: analyticRuleTemplateSpecName12 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'Azure Activity Analytics Rule 12 with template' + displayName: 'Azure Activity Analytics Rule template' + } +} + +resource analyticRuleTemplateSpecName12_analyticRuleVersion12 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: analyticRuleTemplateSpec12 + name: '${analyticRuleVersion12}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'AnalyticsRule' + } + properties: { + description: 'TimeSeriesAnomaly_Mass_Cloud_Resource_Deletions_AnalyticalRules Analytics Rule with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: analyticRuleVersion12 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.SecurityInsights/AlertRuleTemplates' + name: analyticRulecontentId12 + apiVersion: '2022-04-01-preview' + kind: 'Scheduled' + location: workspace_location + properties: { + description: 'This query generates the baseline pattern of cloud resource deletions by an individual and generates an anomaly when any unusual spike is detected. These anomalies from unusual or privileged users could be an indication of a cloud infrastructure takedown by an adversary.' + displayName: 'Mass Cloud resource deletions Time Series Anomaly' + enabled: false + query: 'let starttime = 14d;\nlet endtime = 1d;\nlet timeframe = 1d;\nlet TotalEventsThreshold = 25;\nlet TimeSeriesData = AzureActivity \n| where TimeGenerated between (startofday(ago(starttime))..startofday(now())) \n| where OperationNameValue endswith "delete" \n| project TimeGenerated, Caller \n| make-series Total = count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step timeframe by Caller;\nTimeSeriesData \n| extend (anomalies, score, baseline) = series_decompose_anomalies(Total, 3, -1, \'linefit\') \n| mv-expand Total to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long) \n| where TimeGenerated >= startofday(ago(endtime)) \n| where anomalies > 0 \n| project Caller, TimeGenerated, Total, baseline, anomalies, score \n| where Total > TotalEventsThreshold and baseline > 0 \n| join (AzureActivity \n| where TimeGenerated > startofday(ago(endtime)) \n| where OperationNameValue endswith "delete" \n| summarize count(), make_set(OperationNameValue,100), make_set(_ResourceId,100) by bin(TimeGenerated, timeframe), Caller ) on TimeGenerated, Caller \n| extend Name = iif(Caller has \'@\',tostring(split(Caller,\'@\',0)[0]),"")\n| extend UPNSuffix = iif(Caller has \'@\',tostring(split(Caller,\'@\',1)[0]),"")\n| extend AadUserId = iif(Caller !has \'@\',Caller,"")\n' + queryFrequency: 'P1D' + queryPeriod: 'P14D' + severity: 'Medium' + suppressionDuration: 'PT1H' + suppressionEnabled: false + triggerOperator: 'GreaterThan' + triggerThreshold: 0 + status: 'Available' + requiredDataConnectors: [ + { + dataTypes: [ + 'AzureActivity' + ] + connectorId: 'AzureActivity' + } + ] + tactics: [ + 'Impact' + ] + techniques: [ + 'T1485' + ] + entityMappings: [ + { + entityType: 'Account' + fieldMappings: [ + { + columnName: 'Name' + identifier: 'Name' + } + { + columnName: 'UPNSuffix' + identifier: 'UPNSuffix' + } + { + columnName: 'AadUserId' + identifier: 'AadUserId' + } + ] + } + ] + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/AnalyticsRule-${last(split(analyticRuleId12, '/'))}' + properties: { + description: 'Azure Activity Analytics Rule 12' + parentId: analyticRuleId12 + contentId: _analyticRulecontentId12 + kind: 'AnalyticsRule' + version: analyticRuleVersion12 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + } + } + ] + } + } +} + +resource workbookTemplateSpec1 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: workbookTemplateSpecName1 + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'Workbook' + } + properties: { + description: 'Azure Activity Workbook with template' + displayName: 'Azure Activity workbook template' + } +} + +resource workbookTemplateSpecName1_workbookVersion1 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: workbookTemplateSpec1 + name: '${workbookVersion1}' + location: workspace_location + tags: { + 'hidden-sentinelWorkspaceId': workspaceResourceId + 'hidden-sentinelContentType': 'Workbook' + } + properties: { + description: 'AzureActivityWorkbook with template version 2.0.6' + mainTemplate: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: workbookVersion1 + parameters: {} + variables: {} + resources: [ + { + type: 'Microsoft.Insights/workbooks' + name: workbookContentId1 + location: workspace_location + kind: 'shared' + apiVersion: '2021-08-01' + metadata: { + description: 'Gain extensive insight into your organization\'s Azure Activity by analyzing, and correlating all user operations and events.\nYou can learn about all user operations, trends, and anomalous changes over time.\nThis workbook gives you the ability to drill down into caller activities and summarize detected failure and warning events.' + } + properties: { + displayName: workbook1_name + serializedData: '{"version":"Notebook/1.0","items":[{"type":9,"content":{"version":"KqlParameterItem/1.0","query":"","crossComponentResources":"[variables(\'TemplateEmptyArray\')]","parameters":[{"id":"52bfbd84-1639-480c-bda5-bfc87fd81832","version":"KqlParameterItem/1.0","name":"TimeRange","type":4,"isRequired":true,"value":{"durationMs":604800000},"typeSettings":{"selectableValues":[{"durationMs":300000},{"durationMs":900000},{"durationMs":1800000},{"durationMs":3600000},{"durationMs":14400000},{"durationMs":43200000},{"durationMs":86400000},{"durationMs":172800000},{"durationMs":259200000},{"durationMs":604800000},{"durationMs":1209600000},{"durationMs":2419200000},{"durationMs":2592000000},{"durationMs":5184000000},{"durationMs":7776000000}]}},{"id":"eeb5dcf9-e898-46af-9c12-d91d97e13cd3","version":"KqlParameterItem/1.0","name":"Caller","type":2,"isRequired":true,"multiSelect":true,"quote":"\'","delimiter":",","query":"AzureActivity\\r\\n| summarize by Caller","value":["value::all"],"typeSettings":{"additionalResourceOptions":["value::all"],"selectAllValue":"All"},"timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces"},{"id":"46375a76-7ae1-4d7e-9082-4191531198a9","version":"KqlParameterItem/1.0","name":"ResourceGroup","type":2,"isRequired":true,"multiSelect":true,"quote":"\'","delimiter":",","query":"AzureActivity\\r\\n| summarize by ResourceGroup","value":["value::all"],"typeSettings":{"resourceTypeFilter":{"microsoft.resources/resourcegroups":true},"additionalResourceOptions":["value::all"],"selectAllValue":"All"},"timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces"}],"style":"pills","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces"},"name":"parameters - 2"},{"type":3,"content":{"version":"KqlItem/1.0","query":"let data = AzureActivity\\r\\n| where \\"{Caller:lable}\\" == \\"All\\" or \\"{Caller:lable}\\" == \\"All\\" or Caller in ({Caller})\\r\\n| where \\"{ResourceGroup:lable}\\" == \\"All\\" or \\"{ResourceGroup:lable}\\" == \\"All\\" or ResourceGroup in ({ResourceGroup});\\r\\ndata\\r\\n| summarize Count = count() by ResourceGroup\\r\\n| join kind = fullouter (datatable(ResourceGroup:string)[\'Medium\', \'high\', \'low\']) on ResourceGroup\\r\\n| project ResourceGroup = iff(ResourceGroup == \'\', ResourceGroup1, ResourceGroup), Count = iff(ResourceGroup == \'\', 0, Count)\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by ResourceGroup)\\r\\n on ResourceGroup\\r\\n| project-away ResourceGroup1, TimeGenerated\\r\\n| extend ResourceGroups = ResourceGroup\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count() \\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend ResourceGroup = \'All\', ResourceGroups = \'*\' \\r\\n)\\r\\n| order by Count desc\\r\\n| take 10","size":4,"exportToExcelOptions":"visible","title":"Top 10 active resource groups","timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces","visualization":"tiles","tileSettings":{"titleContent":{"columnMatch":"ResourceGroup","formatter":1,"formatOptions":{"showIcon":true}},"leftContent":{"columnMatch":"Count","formatter":12,"formatOptions":{"palette":"auto","showIcon":true},"numberFormat":{"unit":17,"options":{"maximumSignificantDigits":3,"maximumFractionDigits":2}}},"secondaryContent":{"columnMatch":"Trend","formatter":9,"formatOptions":{"palette":"blueOrange","showIcon":true}},"showBorder":false}},"name":"query - 3"},{"type":3,"content":{"version":"KqlItem/1.0","query":"AzureActivity\\r\\n| where \\"{Caller:lable}\\" == \\"All\\" or Caller in ({Caller})\\r\\n| where \\"{ResourceGroup:lable}\\" == \\"All\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize deletions = countif(OperationNameValue hassuffix \\"delete\\"), creations = countif(OperationNameValue hassuffix \\"write\\"), updates = countif(OperationNameValue hassuffix \\"write\\"), Activities = count(OperationNameValue) by bin_at(TimeGenerated, 1h, now())\\r\\n","size":0,"exportToExcelOptions":"visible","title":"Activities over time","color":"gray","timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces","visualization":"linechart","graphSettings":{"type":0}},"name":"query - 1"},{"type":3,"content":{"version":"KqlItem/1.0","query":"AzureActivity\\r\\n| where \\"{Caller:lable}\\" == \\"All\\" or Caller in ({Caller})\\r\\n| where \\"{ResourceGroup:lable}\\" == \\"All\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize deletions = countif(OperationNameValue hassuffix \\"Delete\\"), creations = countif(OperationNameValue hassuffix \\"write\\"), updates = countif(OperationNameValue hassuffix \\"write\\"), Activities = count() by Caller\\r\\n","size":1,"exportToExcelOptions":"visible","title":"Caller activities","timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces","gridSettings":{"formatters":[{"columnMatch":"Caller","formatter":0,"formatOptions":{"showIcon":true}},{"columnMatch":"deletions","formatter":4,"formatOptions":{"showIcon":true,"aggregation":"Count"}},{"columnMatch":"creations","formatter":4,"formatOptions":{"palette":"purple","showIcon":true,"aggregation":"Count"}},{"columnMatch":"updates","formatter":4,"formatOptions":{"palette":"gray","showIcon":true,"aggregation":"Count"}},{"columnMatch":"Activities","formatter":4,"formatOptions":{"palette":"greenDark","linkTarget":"GenericDetails","linkIsContextBlade":true,"showIcon":true,"aggregation":"Count","workbookContext":{"componentIdSource":"workbook","resourceIdsSource":"workbook","templateIdSource":"static","templateId":"https://go.microsoft.com/fwlink/?linkid=874159&resourceId=%2Fsubscriptions%2F44e4eff8-1fcb-4a22-a7d6-992ac7286382%2FresourceGroups%2FSOC&featureName=Workbooks&itemId=%2Fsubscriptions%2F44e4eff8-1fcb-4a22-a7d6-992ac7286382%2Fresourcegroups%2Fsoc%2Fproviders%2Fmicrosoft.insights%2Fworkbooks%2F4c195aec-747f-40bb-addb-934acb3ec646&name=CiscoASA&func=NavigateToPortalFeature&type=workbook","typeSource":"workbook","gallerySource":"workbook"}}}],"sortBy":[{"itemKey":"$gen_bar_updates_3","sortOrder":2}],"labelSettings":"[variables(\'TemplateEmptyArray\')]"}},"name":"query - 1"},{"type":3,"content":{"version":"KqlItem/1.0","query":"AzureActivity \\r\\n| where \\"{Caller:lable}\\" == \\"All\\" or Caller in ({Caller})\\r\\n| where \\"{ResourceGroup:lable}\\" == \\"All\\" or ResourceGroup in ({ResourceGroup})\\r\\n| summarize Informational = countif(Level == \\"Informational\\"), Warning = countif(Level == \\"Warning\\"), Error = countif(Level == \\"Error\\") by bin_at(TimeGenerated, 1h, now())\\r\\n","size":0,"exportToExcelOptions":"visible","title":"Activities by log level over time","color":"redBright","timeContext":{"durationMs":0},"timeContextFromParameter":"TimeRange","queryType":0,"resourceType":"microsoft.operationalinsights/workspaces","visualization":"scatterchart","tileSettings":{"showBorder":false},"graphSettings":{"type":2,"topContent":{"columnMatch":"Error","formatter":12,"formatOptions":{"showIcon":true}},"hivesContent":{"columnMatch":"TimeGenerated","formatter":1,"formatOptions":{"showIcon":true}},"nodeIdField":"Error","sourceIdField":"Error","targetIdField":"Error","nodeSize":"[variables(\'blanks\')]","staticNodeSize":100,"colorSettings":"[variables(\'blanks\')]","groupByField":"TimeGenerated","hivesMargin":5}},"name":"query - 4"}],"fromTemplateId":"sentinel-AzureActivity","$schema":"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json"}\r\n' + version: '1.0' + sourceId: workspaceResourceId + category: 'sentinel' + } + } + { + type: 'Microsoft.OperationalInsights/workspaces/providers/metadata' + apiVersion: '2022-01-01-preview' + name: '${workspace}/Microsoft.SecurityInsights/Workbook-${last(split(workbookId1, '/'))}' + properties: { + description: '@{workbookKey=AzureActivityWorkbook; logoFileName=azureactivity_logo.svg; description=Gain extensive insight into your organization\'s Azure Activity by analyzing, and correlating all user operations and events.\nYou can learn about all user operations, trends, and anomalous changes over time.\nThis workbook gives you the ability to drill down into caller activities and summarize detected failure and warning events.; dataTypesDependencies=System.Object[]; dataConnectorsDependencies=System.Object[]; previewImagesFileNames=System.Object[]; version=2.0.0; title=Azure Activity; templateRelativePath=AzureActivity.json; subtitle=; provider=Microsoft}.description' + parentId: workbookId1 + contentId: _workbookContentId1 + kind: 'Workbook' + version: workbookVersion1 + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + tier: 'Microsoft' + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + link: 'https://support.microsoft.com/' + } + dependencies: { + operator: 'AND' + criteria: [ + { + contentId: 'AzureActivity' + kind: 'DataType' + } + { + contentId: 'AzureActivity' + kind: 'DataConnector' + } + ] + } + } + } + ] + } + } +} + +resource workspace_Microsoft_SecurityInsights_solutionId 'Microsoft.OperationalInsights/workspaces/providers/metadata@2022-01-01-preview' = { + location: workspace_location + properties: { + version: '2.0.6' + kind: 'Solution' + contentSchemaVersion: '2.0.0' + contentId: _solutionId + parentId: _solutionId + source: { + kind: 'Solution' + name: 'Azure Activity' + sourceId: _solutionId + } + author: { + name: 'Microsoft' + email: _email + } + support: { + name: 'Microsoft Corporation' + email: 'support@microsoft.com' + tier: 'Microsoft' + link: 'https://support.microsoft.com/' + } + dependencies: { + operator: 'AND' + criteria: [ + { + kind: 'DataConnector' + contentId: _dataConnectorContentId1 + version: dataConnectorVersion1 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId1 + version: huntingQueryVersion1 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId2 + version: huntingQueryVersion2 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId3 + version: huntingQueryVersion3 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId4 + version: huntingQueryVersion4 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId5 + version: huntingQueryVersion5 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId6 + version: huntingQueryVersion6 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId7 + version: huntingQueryVersion7 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId8 + version: huntingQueryVersion8 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId9 + version: huntingQueryVersion9 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId10 + version: huntingQueryVersion10 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId11 + version: huntingQueryVersion11 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId12 + version: huntingQueryVersion12 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId13 + version: huntingQueryVersion13 + } + { + kind: 'HuntingQuery' + contentId: _huntingQuerycontentId14 + version: huntingQueryVersion14 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId1 + version: analyticRuleVersion1 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId2 + version: analyticRuleVersion2 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId3 + version: analyticRuleVersion3 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId4 + version: analyticRuleVersion4 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId5 + version: analyticRuleVersion5 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId6 + version: analyticRuleVersion6 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId7 + version: analyticRuleVersion7 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId8 + version: analyticRuleVersion8 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId9 + version: analyticRuleVersion9 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId10 + version: analyticRuleVersion10 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId11 + version: analyticRuleVersion11 + } + { + kind: 'AnalyticsRule' + contentId: analyticRulecontentId12 + version: analyticRuleVersion12 + } + { + kind: 'Workbook' + contentId: _workbookContentId1 + version: workbookVersion1 + } + ] + } + firstPublishDate: '2022-04-18' + providers: [ + 'Microsoft' + ] + categories: { + domains: [ + 'IT Operations' + ] + } + } + name: '${workspace}/Microsoft.SecurityInsights/${_solutionId}' +} + +output hostname string = pip.properties.dnsSettings.fqdn diff --git a/Allfiles/Labs/15/main.bicepparam b/Allfiles/Labs/15/main.bicepparam index b0f80c9..c7d72d3 100644 --- a/Allfiles/Labs/15/main.bicepparam +++ b/Allfiles/Labs/15/main.bicepparam @@ -1,24 +1,24 @@ -using './main.bicep' - -param rgName = 'AZ500LAB131415' -param defenderAutoProvision = 'On' -param defenderAppServicesPricingTier = 'Standard' -param defenderVirtualMachinesPricingTier = 'Standard' -param defenderSqlServersPricingTier = 'Standard' -param defenderStorageAccountsPricingTier = 'Standard' -param defenderDnsPricingTier = 'Standard' -param defenderArmPricingTier = 'Standard' -param PlaybookName = 'Change-Incident-Severity' -param UserName = 'your-username@' -param adminUsername = 'localadmin' -param adminPassword = 'AzureTest01!!' -param publicIpName = 'myPublicIpAddress' -param publicIPAllocationMethod = 'Static' -param publicIpSku = 'Standard' -param OSVersion = '2022-datacenter-azure-edition-core' -param vmSize = 'Standard_D2s_v5' -param location = 'eastus' -param vmName = 'myVM' -param workspace_location = 'eastus' -param workbook1_name = 'Azure Activity' - +using './main.bicep' + +param rgName = 'AZ500LAB131415' +param defenderAutoProvision = 'On' +param defenderAppServicesPricingTier = 'Standard' +param defenderVirtualMachinesPricingTier = 'Standard' +param defenderSqlServersPricingTier = 'Standard' +param defenderStorageAccountsPricingTier = 'Standard' +param defenderDnsPricingTier = 'Standard' +param defenderArmPricingTier = 'Standard' +param PlaybookName = 'Change-Incident-Severity' +param UserName = 'your-username@' +param adminUsername = 'localadmin' +param adminPassword = 'AzureTest01!!' +param publicIpName = 'myPublicIpAddress' +param publicIPAllocationMethod = 'Static' +param publicIpSku = 'Standard' +param OSVersion = '2022-datacenter-azure-edition-core' +param vmSize = 'Standard_D2s_v5' +param location = 'eastus' +param vmName = 'myVM' +param workspace_location = 'eastus' +param workbook1_name = 'Azure Activity' + diff --git a/Instructions/Labs/LAB_03_AzureFirewall.md b/Instructions/Labs/LAB_03_AzureFirewall.md index f7b55fc..0f91fd8 100644 --- a/Instructions/Labs/LAB_03_AzureFirewall.md +++ b/Instructions/Labs/LAB_03_AzureFirewall.md @@ -78,6 +78,7 @@ Azure Firewall을 설치해야 합니다. 조직에서 전체 네트워크 보 |구독|이 랩에서 사용할 Azure 구독의 이름| |Resource group|**새로 만들기**를 클릭하고 **AZ500LAB08**을 이름으로 입력합니다.| |위치|**(미국) 미국 동부**| + |adminPassword|가상 머신을 위해 직접 선택한 보안 암호입니다. 암호를 기억합니다. 나중에 VM에 연결하려면 이 정보가 필요합니다.| >**참고**: Azure VM을 프로비전할 수 있는 Azure 지역을 식별하려면 [ **https://azure.microsoft.com/en-us/regions/offers/** ](https://azure.microsoft.com/en-us/regions/offers/)를 참조하세요. @@ -271,7 +272,7 @@ Azure Firewall을 설치해야 합니다. 조직에서 전체 네트워크 보 |설정|값| |---|---| |사용자 이름|**localadmin**| - |암호|**Pa55w.rd1234**| + |암호|작업 6의 1단계에서 사용자 지정 템플릿을 배포하는 동안 선택한 보안 암호입니다.| >**참고**: 다음 단계는 **Srv-Jump** Azure VM에 대해 원격 데스크톱 세션에서 수행됩니다. @@ -288,7 +289,7 @@ Azure Firewall을 설치해야 합니다. 조직에서 전체 네트워크 보 |설정|값| |---|---| |사용자 이름|**localadmin**| - |암호|**Pa55w.rd1234**| + |암호|작업 6의 1단계에서 사용자 지정 템플릿을 배포하는 동안 선택한 보안 암호입니다.| >**참고**: 원격 데스크톱 세션이 설정되고 서버 관리자 인터페이스가 로드될 때까지 기다립니다. diff --git a/Instructions/Labs/LAB_06_SecuringAzureStorage.MD b/Instructions/Labs/LAB_06_SecuringAzureStorage.MD index ddc2243..11d4d44 100644 --- a/Instructions/Labs/LAB_06_SecuringAzureStorage.MD +++ b/Instructions/Labs/LAB_06_SecuringAzureStorage.MD @@ -9,7 +9,7 @@ lab: ## 랩 시나리오 -Azure 파일 공유 보안을 입증하기 위해 개념 증명을 만들라는 메시지가 표시됩니다. 특히 다음을 수행해야 합니다. +Azure 파일 공유 보안을 입증하기 위한 개념 증명을 생성하라는 요청을 받았습니다. 특히 다음을 수행해야 합니다. - Azure Storage로 향하는 트래픽이 항상 Azure 백본 네트워크 내에 유지되도록 스토리지 엔드포인트를 만듭니다. - 특정 서브넷의 리소스만 스토리지에 액세스할 수 있도록 스토리지 엔드포인트를 구성합니다. @@ -95,7 +95,7 @@ Azure 파일 공유 보안을 입증하기 위해 개념 증명을 만들라는 |서브넷 이름|**프라이빗** | |서브넷 주소 범위|**10.0.1.0/24**| - |서비스 엔드포인트|**Microsoft.Storage**| + |서비스 엔드포인트|**기본값 없을 그대로 유지**| 6. **서브넷 추가** 블레이드에서 **저장**을 클릭하여 새 서브넷을 추가합니다. diff --git a/Instructions/Labs/LAB_07_KeyVaultImplementingSecureDatabysettingupAlwaysEncrypted (2).md b/Instructions/Labs/LAB_07_KeyVaultImplementingSecureDatabysettingupAlwaysEncrypted (2).md new file mode 100644 index 0000000..8c5bc06 --- /dev/null +++ b/Instructions/Labs/LAB_07_KeyVaultImplementingSecureDatabysettingupAlwaysEncrypted (2).md @@ -0,0 +1,509 @@ +--- +lab: + title: 07 - Key Vault(Always Encrypted를 설정하여 안전한 데이터 구현) + module: Module 01 - Manage security operations +--- + +# 랩 07: Key Vault(Always Encrypted를 설정하여 보안 데이터 구현) +# 학생용 랩 매뉴얼 + +## 랩 시나리오 + +Always Encrypted 기능에 대한 Azure SQL Database 지원을 사용하는 개념 증명 애플리케이션을 만들어야 합니다. 이 시나리오에 사용된 모든 비밀과 키는 Key Vault에 저장해야 합니다. 보안 태세를 강화하기 위해서는 해당 애플리케이션을 Microsoft Entra ID에 등록해야 합니다. 이러한 목표를 달성하기 위해 개념 증명에는 다음이 포함되어야 합니다. + +- Azure Key Vault를 만들어 자격 증명 모음에 키 및 비밀을 저장합니다. +- Always Encrypted를 사용하여 SQL Database를 만들고 데이터베이스 테이블의 열 콘텐츠를 암호화합니다. + +>**참고**: 이 랩의 모든 리소스에 대해 **미국 동부** 지역을 사용하고 있습니다. 이 지역을 수업에 사용할 것인지 강사에게 확인합니다. + +이 개념 증명 빌드와 관련된 Azure의 보안 측면에 계속 집중하기 위해 자동화된 ARM 템플릿 배포부터 시작하여 Visual Studio 2019 및 SQL Server Management Studio 19를 사용하여 가상 머신을 설정합니다. + +## 랩 목표 + +이 랩에서는 다음과 같은 연습을 완료합니다: + +- 연습 1: ARM 템플릿에서 기본 인프라 배포 +- 연습 2: 키와 비밀을 사용하여 Key Vault 리소스 구성 +- 연습 3: Azure SQL 데이터베이스 및 데이터 기반 애플리케이션 구성 +- 연습 4: Azure SQL 데이터베이스 암호화 과정에서 Azure Key Vault를 사용하는 방법 시연 + +## Key Vault 다이어그램 + +![이미지](https://github.com/MicrosoftLearning/AZ500-AzureSecurityTechnologies/assets/91347931/38c4ba6d-2fc7-45e5-b9a2-d5dbb4fbbcbc) + +## Instructions + +## 랩 파일: + +- **\\Allfiles\\Labs\\10\\az-500-10_azuredeploy.json** + +- **\\Allfiles\\Labs\\10\\program.cs** + +### 총 랩 소요 시간(예상): 60분 + +### 연습 1: ARM 템플릿에서 기본 인프라 배포 + +이 연습에서는 다음 작업을 완료합니다. + +- 작업 1: Azure VM 및 Azure SQL 데이터베이스 배포 + +#### 작업 1: Azure VM 및 Azure SQL 데이터베이스 배포 + +이 작업에서는 배포의 일부로 Visual Studio 2019 및 SQL Server Management Studio 19를 자동으로 설치하는 Azure VM을 배포합니다. + +1. Azure portal **`https://portal.azure.com/`** 에 로그인합니다. + + >**참고**: 이 랩에 사용 중인 Azure 구독에 Owner 또는 Contributor 역할이 있는 계정을 사용하여 Azure Portal에 로그인합니다. + +2. Azure Portal에서 Azure Portal 페이지 위쪽의 **리소스, 서비스 및 문서 검색** 텍스트 상자에 **사용자 지정 템플릿 배포**를 입력하고 **Enter** 키를 누릅니다. + +3. **사용자 지정 배포** 블레이드에서 **편집기에서 사용자 고유의 탬플릿 빌드** 옵션을 클릭합니다. + +4. **템플릿 편집** 블레이드에서 **파일 로드**를 클릭하고 **\\Allfiles\\Labs\\10\\az-500-10_azuredeploy.json** 파일을 찾아 **열기**를 클릭합니다. + +5. **템플릿 편집** 블레이드에서 **저장**을 클릭합니다. + +6. **사용자 지정 배포** 블레이드의 **배포 범위**에서 다음 설정이 구성되어 있는지 확인합니다. 다른 설정은 모두 기본값으로 유지합니다. + + |설정|값| + |---|---| + |구독|이 랩에서 사용할 Azure 구독의 이름| + |Resource group|**새로 만들기**를 클릭하고 **AZ500LAB10**을 이름으로 입력합니다.| + |위치|**미국 동부**| + |사용자 이름|**학생**| + |암호|**랩 02 > 연습 2 > 작업 1 > 3단계에서 만든 개인 암호를 사용하세요.**| + + + >**참고**: 가상 머신에 로그온하는 데 사용하는 관리 자격 증명을 변경할 수는 있지만 반드시 변경할 필요는 없습니다. + + >**참고**: Azure VM을 프로비전할 수 있는 Azure 지역을 식별하려면 [ **https://azure.microsoft.com/en-us/regions/offers/** ](https://azure.microsoft.com/en-us/regions/offers/)를 참조하세요. + +8. **검토 및 만들기** 단추를 클릭한 후에 **만들기** 단추를 클릭하여 배포를 확인합니다. + + >**참고**: 이렇게 하면 이 랩에 필요한 Azure VM 및 Azure SQL 데이터베이스 배포가 시작됩니다. + + >**참고**: ARM 템플릿 배포가 완료될 때까지 기다리지 말고 다음 연습을 진행하세요. 배포는 **20~25분** 정도 걸릴 수 있습니다. + +### 연습 2: 키와 비밀을 사용하여 Key Vault 리소스 구성 + +>**참고**: 이 랩의 모든 리소스에 대해 **미국 동부** 지역을 사용하고 있습니다. 강사에게 이 지역을 수업에서 사용하는지 확인합니다. + +이 연습에서는 다음 작업을 완료합니다. + +- 작업 1: Key Vault 만들기 및 구성 +- 작업 2: Key Vault에 키 추가 +- 작업 3: Key Vault에 암호 추가 + +#### 작업 1: Key Vault 만들기 및 구성 + +이 작업에서는 Azure Key Vault 리소스를 만듭니다. 그리고 Azure Key Vault 권한도 구성합니다. + +1. Azure Portal 오른쪽 위의 검색 창 옆에 있는 첫 번째 아이콘을 클릭하여 Cloud Shell을 엽니다. 메시지가 표시되면 **PowerShell** 및 **스토리지 만들기**를 선택합니다. + +2. Cloud Shell 창의 왼쪽 위 모서리에 있는 드롭다운 메뉴에서 **PowerShell**이 선택되었는지 확인합니다. + +3. Cloud Shell 창 내의 PowerShell 세션에서 다음 명령을 실행하여 리소스 그룹 **AZ500LAB10**에 Azure Key Vault를 만듭니다. 작업 1에서 이 랩의 리소스 그룹에 다른 이름을 선택했다면 이 작업에서도 해당 이름을 사용하세요. Key Vault 이름은 고유해야 합니다. 선택한 이름을 기억하세요. 이 랩에서 필요합니다. + + ```powershell + $kvName = 'az500kv' + $(Get-Random) + + $location = (Get-AzResourceGroup -ResourceGroupName 'AZ500LAB10').Location + + New-AzKeyVault -VaultName $kvName -ResourceGroupName 'AZ500LAB10' -Location $location + ``` + + >**참고**: 마지막으로 실행된 명령의 출력에 자격 증명 모음 이름과 URI가 표시됩니다. 자격 증명 모음 URI는 `https://.vault.azure.net/` 형식입니다. + +4. Cloud Shell 창을 닫습니다. + +5. Azure Portal에서 Azure Portal 페이지 위쪽의 **리소스, 서비스 및 문서 검색** 텍스트 상자에 **리소스 그룹**을 입력하고 **Enter** 키를 누릅니다. + +6. **리소스 그룹** 블레이드의 리소스 그룹 목록에서 **AZ500LAB10** 항목이나 이전 작업에서 리소스 그룹용으로 선택한 다른 이름을 클릭합니다. + +7. 리소스 그룹 블레이드에서 새로 만든 Key Vault를 나타내는 항목을 클릭합니다. + +8. Key Vault 블레이드의 **개요** 섹션에서 **액세스 정책**을 클릭한 다음, **+ 만들기**를 클릭합니다. + +9. **액세스 정책 만들기** 블레이드에서 다음 설정을 지정합니다(다른 모든 설정을 기본값으로 남겨둠). + + |설정|값| + |----|----| + |템플릿에서 구성(선택 사항)|**키, 비밀 및 인증서 관리**| + |키 권한|**모두 선택**을 클릭하면 총 **9개 선택** 권한이 생성됩니다.| + |주요 권한/암호화 작업|**서명**을 클릭하면 총 **1개 선택** 권한이 생성됩니다.| + |비밀 권한|**모두 선택**을 클릭하면 총 **7개의 선택된** 권한이 나타납니다.| + |인증 권한|**모두 선택**을 클릭하면 총 **15개의 선택된** 권한이 나타납니다.| + |보안 주체 선택|**선택된 항목 없음**을 클릭하고, **보안 주체** 블레이드에서 사용자 계정을 선택하고 **다음**을 클릭합니다.| + |애플리케이션(선택 사항)|**다음**을 누릅니다| + |검토 + 만들기|**만들기**를 클릭합니다.| + + >**참고**: 이전 검토 + 만들기 작업은 애플리케이션, 메일, 키 권한, 비밀 권한, 인증서 권한을 나열하는 액세스 정책 페이지로 돌아갑니다. + +#### 작업 2: Key Vault에 키 추가 + +이 작업에서는 Key Vault에 키를 추가하고 키에 대한 정보를 확인합니다. + +1. Azure Portal의 Cloud Shell 창에서 PowerShell 세션을 엽니다. + +2. Cloud Shell 창의 왼쪽 위 드롭다운 메뉴에서 **PowerShell**이 선택되어 있는지 확인합니다. + +3. Cloud Shell 창 내의 PowerShell 세션에서 다음을 실행하여 Key Vault에 소프트웨어로 보호된 키를 추가합니다. + + ```powershell + $kv = Get-AzKeyVault -ResourceGroupName 'AZ500LAB10' + + $key = Add-AZKeyVaultKey -VaultName $kv.VaultName -Name 'MyLabKey' -Destination 'Software' + ``` + + >**참고**: 키 이름은 **MyLabKey**입니다. + +4. Cloud Shell 창 내의 PowerShell 세션에서 다음을 실행하여 키가 만들어졌는지 확인합니다. + + ```powershell + Get-AZKeyVaultKey -VaultName $kv.VaultName + ``` + +5. Cloud Shell 창 내의 PowerShell 세션에서 다음을 실행하여 키 식별자를 표시합니다. + + ```powershell + $key.key.kid + ``` + +6. Cloud Shell 창을 최소화합니다. + +7. Azure Portal로 돌아와서 Key Vault 블레이드의 **개체** 섹션에서 **키**를 클릭합니다. + +8. 키 목록에서 **MyLabKey** 항목을 클릭한 다음 **MyLabKey** 블레이드에서 키의 현재 버전을 나타내는 항목을 클릭합니다. + + >**참고**: 만든 키와 관련된 정보를 점검합니다. + + >**참고**: 키 식별자를 사용하여 모든 키를 참조할 수 있습니다. 최신 버전을 얻으려면 `https://.vault.azure.net/keys/MyLabKey`를 참조하거나 `https://.vault.azure.net/keys/MyLabKey/`을 사용하여 특정 버전을 가져옵니다. + + +#### 작업 3: Key Vault에 비밀 추가 + +1. Cloud Shell 창으로 다시 전환합니다. + +2. Cloud Shell 창 내의 PowerShell 세션에서 다음을 실행하여 보안 문자열 값이 있는 변수를 만듭니다. + + ```powershell + $secretvalue = ConvertTo-SecureString 'Pa55w.rd1234' -AsPlainText -Force + ``` + +3. Cloud Shell 창 내의 PowerShell 세션에서 다음을 실행하여 자격 증명 모음에 암호를 추가합니다. + + ```powershell + $secret = Set-AZKeyVaultSecret -VaultName $kv.VaultName -Name 'SQLPassword' -SecretValue $secretvalue + ``` + + >**참고**: 암호의 이름은 SQLPassword입니다. + +4. Cloud Shell 창 내의 PowerShell 세션에서 다음을 실행하여 비밀이 만들어졌는지 확인합니다. + + ```powershell + Get-AZKeyVaultSecret -VaultName $kv.VaultName + ``` + +5. Cloud Shell 창을 최소화합니다. + +6. Azure Portal에서 Key Vault 블레이드로 다시 이동하여 **개체** 섹션에서 **비밀**을 클릭합니다. + +7. 비밀 목록에서 **SQLPassword** 항목을 클릭한 다음 **SQLPassword** 블레이드에서 현재 버전의 비밀을 나타내는 항목을 클릭합니다. + + >**참고**: 만든 비밀과 관련된 정보를 점검합니다. + + >**참고**: 최신 버전의 비밀을 얻으려면 `https://.vault.azure.net/secrets/`을 참조하고, 특정 버전을 얻으려면 `https://.vault.azure.net/secrets//`을 참조합니다. + + +### 연습 3: Azure SQL 데이터베이스 및 데이터 기반 애플리케이션 구성 + +이 연습에서는 다음 작업을 완료합니다. + +- 작업 1: 클라이언트 애플리케이션이 Azure SQL Database 서비스에 액세스할 수 있도록 설정 +- 작업 2: 애플리케이션의 Key Vault 액세스를 허용하는 정책 만들기 +- 작업 3: SQL Azure 데이터베이스 ADO.NET 연결 문자열 검색 +- 작업 4: Visual Studio 2019 및 SQL Management Studio 19를 실행하는 Azure VM에 로그온합니다. +- 작업 5: SQL Database에서 테이블을 만들고 암호화를 위한 데이터 열을 선택합니다. + + +#### 작업 1: 클라이언트 애플리케이션이 Azure SQL Database 서비스에 액세스할 수 있도록 설정 + +이 작업에서는 클라이언트 애플리케이션이 Azure SQL Database 서비스에 액세스할 수 있도록 설정합니다. 이렇게 하려면 필요한 인증을 설정하고, 애플리케이션을 인증하는 데 필요한 애플리케이션 ID 및 비밀을 가져옵니다. + +1. Azure Portal에서 Azure Portal 페이지 위쪽의 **리소스, 서비스 및 문서 검색** 텍스트 상자에서 **앱 등록**을 입력하고 **Enter** 키를 누릅니다. + +2. **앱 등록** 블레이드에서 **+ 새 등록**을 클릭합니다. + +3. **애플리케이션 등록** 블레이드에서 다음 설정을 지정합니다(다른 모든 설정을 기본값으로 남겨둡니다). + + |설정|값| + |----|----| + |이름|**sqlApp**| + |리디렉션 URI(선택 사항)|**웹** 및 **https://sqlapp**| + +4. **애플리케이션 등록** 블레이드에서 **등록**을 클릭합니다. + + >**참고**: 등록이 완료되면 브라우저가 자동으로 **sqlApp**블레이드로 리디렉션합니다. + +5. **sqlApp** 블레이드에서 **애플리케이션(클라이언트) ID**의 값을 식별합니다. + + >**참고**: 이 값을 기록해 둡니다. 다음 작업에서 필요합니다. + +6. **sqlApp** 블레이드의 **관리** 섹션에서 **인증서 및 비밀**을 클릭합니다. + +7. **인증서 및 비밀** 블레이드의 **클라이언트 비밀** 섹션에서 **+ 새 클라이언트 암호**를 클릭합니다. + +8. **클라이언트 암호 추가** 창에서 다음 설정을 지정합니다. + + |설정|값| + |----|----| + |설명|**Key1**| + |만료|**12개월**| + +9. 애플리케이션 자격 증명을 업데이트하려면 **추가**를 클릭합니다. + +10. **sqlApp | 인증서 및 비밀** 블레이드에서 **Key1**의 값을 식별합니다. + + >**참고**: 이 값을 기록해 둡니다. 다음 작업에서 필요합니다. + + >**참고**: 블레이드에서 멀리 *이동*하기 전에 값을 복사해야 합니다. 이렇게 하면 키의 일반 텍스트 값을 더 이상 검색할 수 없습니다. + + +#### 작업 2: 애플리케이션의 Key Vault 액세스를 허용하는 정책 만들기 + +이 작업에서는 Key Vault에 저장된 비밀 액세스 권한을 새로 등록된 앱에 부여합니다. + +1. Azure Portal의 Cloud Shell 창에서 PowerShell 세션을 엽니다. + +2. Cloud Shell 창의 왼쪽 위 드롭다운 메뉴에서 **PowerShell**이 선택되어 있는지 확인합니다. + +3. Cloud Shell 창 내의 PowerShell 세션에서 다음을 실행하여 이전 작업에서 기록한 **애플리케이션(클라이언트) ID**를 저장하는 변수를 만듭니다(`` 자리 표시자를 **애플리케이션(클라이언트) ID**의 값으로 대체). + + ```powershell + $applicationId = '' + ``` +4. Cloud Shell 창 내의 PowerShell 세션에서 다음 명령을 실행하여 Key Vault 이름을 저장하는 변수를 만듭니다. + ``` + $kvName = (Get-AzKeyVault -ResourceGroupName 'AZ500LAB10').VaultName + + $kvName + ``` + +5. Cloud Shell 창의 PowerShell 세션에서 다음 명령을 실행하여 이전 작업에서 등록한 애플리케이션에 Key Vault 관련 권한을 부여합니다. + + ```powershell + Set-AZKeyVaultAccessPolicy -VaultName $kvName -ResourceGroupName AZ500LAB10 -ServicePrincipalName $applicationId -PermissionsToKeys get,wrapKey,unwrapKey,sign,verify,list + ``` + +6. Cloud Shell 창을 닫습니다. + + +#### 작업 3: SQL Azure 데이터베이스 ADO.NET 연결 문자열 검색 + +연습 1에서 ARM 템플릿을 배포할 때 Azure SQL Server 인스턴스 및 Azure SQL 데이터베이스(**medical**)가 프로비전되었습니다. 이제 새 테이블 구조를 적용하여 빈 데이터베이스 리소스를 업데이트하고 암호화용 데이터 열을 선택합니다. + +1. Azure Portal의 페이지 상단에 있는 **리소스, 서비스 및 문서 검색** 텍스트 상자에서 **SQL 데이터베이스**를 입력하고 **Enter** 키를 누릅니다. + +2. SQL 데이터베이스 목록에서 **medical()** 항목을 클릭합니다. + + >**참고**: 데이터베이스를 찾을 수 없으면 연습 1에서 시작한 배포가 아직 완료되지 않았을 가능성이 높습니다. Azure 리소스 그룹 "AZ500LAB10" 또는 선택한 이름의 그룹으로 이동한 다음 설정 창에서 **배포**를 선택하면 배포 완료 여부를 확인할 수 있습니다. + +3. SQL Database 블레이드의 **설정** 섹션에서 **연결 문자열**을 클릭합니다. + + >**참고**: 인터페이스에는 ADO.NET, JDBC, ODBC, PHP 및 Go용 연결 문자열이 포함됩니다. + +4. **ADO.NET(SQL 인증)** 연결 문자열을 기록합니다. 이 시간은 나중에 필요합니다. + + >**참고**: 연결 문자열을 사용하는 경우 `{your_password}` 자리 표시자를 연습 1의 배포에서 구성한 암호로 바꿔야 합니다. + +#### 작업 4: Visual Studio 2019 및 SQL Management Studio 19를 실행하는 Azure VM에 로그온합니다. + +이 작업에서는 연습 1에서 배포를 시작한 Azure VM에 로그온합니다. 이 Azure VM은 Visual Studio 2019 및 SQL Server Management Studio 19를 호스팅합니다. + + >**Note**: Before you proceed with this task, ensure that the deployment you initiated in the first exercise has completed successfully. You can validate this by navigating to the blade of the Azure resource group "Az500Lab10" (or other name you chose) and selecting **Deployments** from the Settings pane. + +1. Azure Portal 페이지 위쪽의 **리소스, 서비스 및 문서 검색** 텍스트 상자에 **가상 머신**을 입력하고 **Enter** 키를 누릅니다. + +2. 표시된 가상 머신 목록에서 **az500-10-vm1** 항목을 선택합니다. **az500-10** 블레이드의 **필수** 창에서 **공용 IP 주소**를 클릭합니다. 나중에 수행할 작업에서 이 주소를 사용합니다. + +#### 작업 5: SQL Database에서 테이블을 만들고 암호화를 위한 데이터 열을 선택합니다. + +이 작업에서는 SQL Server Management Studio를 사용하여 SQL Database에 연결하고 테이블을 만듭니다. 그런 다음 Azure Key Vault에서 자동 생성된 키를 사용하여 데이터 열 두 개를 암호화합니다. + +1. Azure Portal에서 **medical** SQL 데이터베이스의 블레이드로 이동하여 **필수** 섹션에서 **서버 이름**(클립보드에 복사)을 확인한 다음 도구 모음에서 **서버 방화벽 설정**을 클릭합니다. + + >**참고**: 서버 이름을 기록합니다. 이 작업의 후반에서 필요할 것입니다. + +2. **방화벽 설정** 블레이드에서 규칙 이름까지 아래로 스크롤하고 **+ 방화벽 규칙 추가**를 클릭한 후 다음 설정을 지정합니다. + + |설정|값| + |---|---| + |규칙 이름|**관리 VM 허용**| + |시작 IP|az500-10-vm1의 공용 IP 주소| + |종료 IP|az500-10-vm1의 공용 IP 주소| + +3. **저장**을 클릭하여 변경 내용을 저장하고 확인 창을 닫습니다. + + >**참고**: 이렇게 하면 서버 방화벽 설정이 수정됩니다. 그에 따라 이 랩에서 배포한 Azure VM 공용 IP 주소에서 medical 데이터베이스에 연결할 수 있게 됩니다. + +4. **az500-10-vm1** 블레이드로 다시 이동하여 **개요**, **연결**을 차례로 클릭하고 드롭다운 메뉴에서 **RDP**를 클릭합니다. + +5. **RDP 파일 다운로드**를 클릭하고 원격 데스크톱을 통해 **az500-10-vm1** Azure VM에 연결하는 데 사용합니다. 인증하라는 메시지가 표시되면 다음 자격 증명을 입력합니다. + + |설정|값| + |---|---| + |사용자 이름|**학생**| + |암호|**랩 02 > 연습 1 > 작업 1 > 9단계에서 만든 개인 암호를 사용하세요.**| + + >**참고**: 원격 데스크톱 세션과 **서버 관리자**가 로드될 때까지 기다립니다. 서버 관리자를 닫습니다. + + >**참고**: 이 랩의 나머지 단계는 원격 데스크톱 세션 내에서 **az500-10-vm1** Azure VM에 대해 수행됩니다. + +6. **az500-10-vm1.** 에 [SQL Server Management Studio](https://learn.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?preserve-view=true&view=sql-server-2017)를 설치합니다. Azure VM: + +7. **SQL Server Management Studio**를 엽니다. + +8. **서버에 연결** 대화 상자에서, 다음 설정을 지정합니다. + + |설정|값| + |---|---| + |서버 유형|**데이터베이스 엔진**| + |서버 이름|이 작업의 앞부분에서 식별한 서버 이름| + |인증|**SQL Server 인증**| + |사용자 이름|**학생**| + |암호|**랩 02 > 연습 2 > 작업 1 > 3단계에서 만든 개인 암호를 사용하세요.**| + +9. **서버에 연결** 대화 상자에서 **연결**을 클릭합니다. + +10. **SQL Server Management Studio** 콘솔 내, **개체 탐색기** 창에서 **데이터베이스** 폴더를 확장합니다. + +11. **개체 탐색기** 창에서 **의료** 데이터베이스를 마우스 오른쪽 단추로 클릭하고 **새 쿼리**를 클릭합니다. + +12. 다음 코드를 쿼리 창에 붙여넣고 **실행**을 클릭합니다. 그러면 **Patients** 테이블이 만들어집니다. + + ```sql + CREATE TABLE [dbo].[Patients]( + [PatientId] [int] IDENTITY(1,1), + [SSN] [char](11) NOT NULL, + [FirstName] [nvarchar](50) NULL, + [LastName] [nvarchar](50) NULL, + [MiddleName] [nvarchar](50) NULL, + [StreetAddress] [nvarchar](50) NULL, + [City] [nvarchar](50) NULL, + [ZipCode] [char](5) NULL, + [State] [char](2) NULL, + [BirthDate] [date] NOT NULL + PRIMARY KEY CLUSTERED ([PatientId] ASC) ON [PRIMARY] ); + ``` +13. 테이블이 정상적으로 작성되면 **개체 탐색기** 창에서 **medical** 데이터베이스 노드, **tables** 노드를 차례로 확장하고 **dbo.Patients** 노드를 마우스 오른쪽 단추로 클릭한 다음 **열 암호화**를 클릭합니다. + + >**참고**: 그러면 **Always Encrypted** 마법사가 시작됩니다. + +14. **소개** 페이지에서 **다음**을 클릭합니다. + +15. **열 선택** 페이지에서 **SSN** 및 **Birthdate** 열을 선택하고 **SSN** 열의 **암호화 유형**은 **명확함**으로, **Birthdate** 열의 암호화 유형은 **무작위**로 설정한 후에 **다음**을 클릭합니다. + + >**참고**: 암호화를 수행하는 중에 **호출 대상에 의해 예외가 throw됨** 같이 **Rotary(Microsoft.SQLServer.Management.ServiceManagement)** 와 관련된 오류가 throw되면 **키 권한**의 **순환 정책 작업** 값이 **선택 취소**되어 있는지 확인합니다. 현재 위치가 Azure Portal이 아닌 경우 **Key Vault** >> **액세스 정책** >> **키 권한**으로 이동하고, **순환 정책 작업** 아래에서 모든 값의 선택을 취소한 다음, **권한 있는 키 작업** 아래에서 **해제**를 선택 취소합니다. + +16. **마스터 키 구성** 페이지에서 **Azure Key Vault**를 선택하고 **로그인**을 클릭합니다. 메시지가 표시되면 이 랩의 앞부분에서 Azure Key Vault 인스턴스를 프로비전하는 데 사용한 것과 같은 사용자 계정을 사용하여 인증을 진행합니다. 그런 다음 **Azure Key Vault 선택** 드롭다운 목록에 Key Vault가 표시되는지 확인하고 **다음**을 클릭합니다. + +17. **실행 설정** 페이지에서 **다음**을 클릭합니다. + +18. **요약** 페이지에서 **마침**을 클릭하여 암호화를 진행합니다. 메시지가 표시되면 이 랩의 앞부분에서 Azure Key Vault 인스턴스 프로비전에 사용한 것과 동일한 사용자 계정을 사용하여 다시 로그인합니다. + +19. 암호화 프로세스가 완료되면 **결과** 페이지에서 **닫기**를 클릭합니다. + +20. **SQL Server Management Studio** 콘솔의 **개체 탐색기** 창에서 **medical** 노드 아래에 있는 **보안** 및 **항상 암호화 키** 하위 노드를 확장합니다. + + >**참고**: **항상 암호화 키** 하위 노드에는 **열 마스터 키** 및 **열 암호화 키** 하위 폴더가 포함되어 있습니다. + + +### 연습 4: Azure SQL 데이터베이스 암호화 과정에서 Azure Key Vault를 사용하는 방법 시연 + +이 연습에서는 다음 작업을 완료합니다. + +- 작업 1: 데이터 기반 애플리케이션을 실행하여 Azure SQL 데이터베이스 암호화 과정에서 Azure Key Vault를 사용하는 방법 시연 + +#### 작업 1: 데이터 기반 애플리케이션을 실행하여 Azure SQL 데이터베이스 암호화 과정에서 Azure Key Vault를 사용하는 방법 시연 + +이 작업에서는 Visual Studio를 사용하여 콘솔 애플리케이션을 만들어 암호화된 열에 데이터를 로드합니다. 그런 다음 Key Vault의 키에 액세스하는 연결 문자열을 사용하여 해당 데이터에 안전하게 액세스합니다. + +1. **az500-10-vm1**로의 RDP 세션 **시작 메뉴**에서 **Visual Studio 2019**를 시작합니다. + +2. Visual Studio 2019 시작 메시지가 표시된 창으로 전환하여 **로그인** 단추를 클릭합니다. 메시지가 표시되면 이 랩에서 사용 중인 Azure 구독에 인증하는 데 사용한 자격 증명을 입력합니다. + +3. **시작** 페이지에서 **새 프로젝트 만들기**를 클릭합니다. + +4. 프로젝트 템플릿 목록에서 **콘솔 앱(.NET 프레임워크)** 을 검색하고, 결과 목록에서 **C#** 에 대해 **콘솔 앱(.NET 프레임워크)** 을 클릭한 후 **다음**을 클릭합니다. + +5. **새 프로젝트 구성** 페이지에서 다음 설정을 지정하고(다른 설정은 기본값으로 남겨둠) **만들기**를 클릭합니다. + + |설정|값| + |---|---| + |프로젝트 이름|**OpsEncrypt**| + |솔루션 이름|**OpsEncrypt**| + |프레임워크|**.NET Framework 4.7.2**| + +6. Visual Studio 콘솔에서 **도구** 메뉴를 클릭하고, 드롭다운 메뉴에서 **NuGet 패키지 관리자**를 클릭한 후 계단식 메뉴에서 **패키지 관리자 콘솔**을 클릭합니다. + +7. **패키지 관리자 콘솔** 창에서 다음을 실행하여 첫 번째 필수 **NuGet** 패키지를 설치합니다. + + ```powershell + Install-Package Microsoft.SqlServer.Management.AlwaysEncrypted.AzureKeyVaultProvider + ``` + +8. **패키지 관리자 콘솔** 창에서 다음을 실행하여 두 번째 필수 **NuGet** 패키지를 설치합니다. + + ```powershell + Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory + ``` + +9. Azure 가상 머신에 대한 RDP 세션을 최소화한 다음, **\\Allfiles\\Labs\\10\\program.cs**로 이동하고, 파일을 메모장에서 열고, 콘텐츠를 클립보드에 복사합니다. + +10. RDP 세션으로 돌아가고 Visual Studio 콘솔의 **솔루션 탐색기** 창에서 **Program.cs**를 클릭하고, 해당 콘텐츠를 클립보드에 복사한 코드로 바꿉니다. + +11. Visual Studio 창에서 **Program.cs** 창의 줄 15에서 `` 자리 표시자를 랩의 앞부분에서 기록한 Azure SQL Database **ADO.NET** 연결 문자열로 바꿉니다. 연결 문자열에서 `{your_password}` 자리 표시자를 연습 1의 배포에서 지정한 암호로 바꿉니다. 랩 컴퓨터에 문자열을 저장한 경우 RDP 세션을 떠나서 ADO 문자열을 복사한 다음, Azure 가상 머신으로 돌아가서 붙여 넣어야 할 수 있습니다. + +12. Visual Studio 창에서 **Program.cs** 창의 줄 16에서 `` 자리 표시자를 랩의 앞부분에서 기록한 등록된 앱의 **애플리케이션(클라이언트) ID** 값으로 바꿉니다. + +13. Visual Studio 창에서 **Program.cs** 창의 줄 17에서 `` 자리 표시자를 랩의 앞부분에서 기록한 등록된 앱의 **Key1** 값으로 바꿉니다. + +14. Visual Studio 콘솔에서 **시작** 단추를 클릭하여 콘솔 애플리케이션의 빌드를 시작합니다. + +15. 애플리케이션은 명령 프롬프트 창을 시작합니다. 암호를 묻는 메시지가 표시되면 연습 1의 배포에서 지정한 암호를 입력하여 Azure SQL Database에 연결합니다. + +16. 콘솔 앱은 실행 중인 상태로 유지하고 **SQL Management Studio** 콘솔로 전환합니다. + +17. **개체 탐색기** 창에서 **medical 데이터베이스**를 마우스 오른쪽 단추로 클릭하고 마우스 오른쪽 클릭 메뉴에서 **새 쿼리**를 클릭합니다. + +18. 쿼리 창에서 다음 쿼리를 실행하여 콘솔 앱의 데이터베이스에 로드된 데이터가 암호화되었는지 확인합니다. + + ```sql + SELECT FirstName, LastName, SSN, BirthDate FROM Patients; + ``` + +19. 이제 콘솔 애플리케이션으로 다시 전환하면 유효한 SSN을 입력하라는 메시지가 표시됩니다. 이 SSN을 입력하면 암호화된 열에서 데이터를 쿼리합니다. 명령 프롬프트에서 다음을 입력하고 Enter 키를 누릅니다. + + ```cmd + 999-99-0003 + ``` + + >**참고**: 쿼리에서 반환된 데이터가 암호화되지 않았는지 확인합니다. + +20. 콘솔 앱을 종료하려면 Enter 키를 누릅니다. + +**리소스 정리** + +> 더 이상 사용하지 않는 새로 만든 Azure 리소스는 모두 제거하세요. 사용하지 않는 리소스를 제거하면 예상하지 못한 비용이 발생하지 않습니다. + +1. Azure Portal 오른쪽 위의 첫 번째 아이콘을 클릭하여 Cloud Shell을 엽니다. + +2. 필요한 경우 Cloud Shell 창의 왼쪽 상단 드롭다운 메뉴에서 **PowerShell**을 선택하고 메시지가 표시되면 **확인**을 클릭합니다. + +3. Cloud Shell 창 내의 PowerShell 세션에서 다음을 실행하여 이 랩에서 만든 리소스 그룹을 제거합니다. + + ```powershell + Remove-AzResourceGroup -Name "AZ500LAB10" -Force -AsJob + ``` + +4. **Cloud Shell** 창을 닫습니다. diff --git a/Instructions/Labs/LAB_07_KeyVaultImplementingSecureDatabysettingupAlwaysEncrypted.md b/Instructions/Labs/LAB_07_KeyVaultImplementingSecureDatabysettingupAlwaysEncrypted.md index 8c5bc06..59d570b 100644 --- a/Instructions/Labs/LAB_07_KeyVaultImplementingSecureDatabysettingupAlwaysEncrypted.md +++ b/Instructions/Labs/LAB_07_KeyVaultImplementingSecureDatabysettingupAlwaysEncrypted.md @@ -105,11 +105,7 @@ Always Encrypted 기능에 대한 Azure SQL Database 지원을 사용하는 개 3. Cloud Shell 창 내의 PowerShell 세션에서 다음 명령을 실행하여 리소스 그룹 **AZ500LAB10**에 Azure Key Vault를 만듭니다. 작업 1에서 이 랩의 리소스 그룹에 다른 이름을 선택했다면 이 작업에서도 해당 이름을 사용하세요. Key Vault 이름은 고유해야 합니다. 선택한 이름을 기억하세요. 이 랩에서 필요합니다. ```powershell - $kvName = 'az500kv' + $(Get-Random) - - $location = (Get-AzResourceGroup -ResourceGroupName 'AZ500LAB10').Location - - New-AzKeyVault -VaultName $kvName -ResourceGroupName 'AZ500LAB10' -Location $location + New-AzKeyVault -VaultName $kvName -ResourceGroupName 'AZ500LAB10-lod41132372' -Location $location -DisableRbacAuthorization ``` >**참고**: 마지막으로 실행된 명령의 출력에 자격 증명 모음 이름과 URI가 표시됩니다. 자격 증명 모음 URI는 `https://.vault.azure.net/` 형식입니다.