diff --git a/azure_jumpstart_arcbox/ARM/mgmt/policyAzureArcBuiltins.json b/azure_jumpstart_arcbox/ARM/mgmt/policyAzureArcBuiltins.json index df9a34f756..e1e98f79ee 100644 --- a/azure_jumpstart_arcbox/ARM/mgmt/policyAzureArcBuiltins.json +++ b/azure_jumpstart_arcbox/ARM/mgmt/policyAzureArcBuiltins.json @@ -28,7 +28,8 @@ "definitionId": "/providers/Microsoft.Authorization/policySetDefinitions/59e9c3eb-d8df-473b-8059-23fd38ddd0f0", "flavors": [ "Full", - "ITPro" + "ITPro", + "DataOps" ], "roleDefinition": [ "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", diff --git a/azure_jumpstart_arcbox/artifacts/ArcServersLogonScript.ps1 b/azure_jumpstart_arcbox/artifacts/ArcServersLogonScript.ps1 index b53b32b940..126e58f136 100644 --- a/azure_jumpstart_arcbox/artifacts/ArcServersLogonScript.ps1 +++ b/azure_jumpstart_arcbox/artifacts/ArcServersLogonScript.ps1 @@ -27,7 +27,7 @@ if ([System.IO.File]::Exists($logFilePath)) { Start-Transcript -Path $logFilePath -Force -ErrorAction SilentlyContinue ################################################ -# Setup Hyper-V server before deploying VMs for each flavr +# Setup Hyper-V server before deploying VMs for each flavor ################################################ if ($Env:flavor -ne "DevOps") { # Install and configure DHCP service (used by Hyper-V nested VMs) @@ -158,10 +158,13 @@ if ($Env:flavor -ne "DevOps") { az monitor log-analytics solution create --resource-group $resourceGroup --solution-type SQLAdvancedThreatProtection --workspace $Env:workspaceName --only-show-errors --no-wait } + # Before deploying ArcBox SQL set resource group tag ArcSQLServerExtensionDeployment=Disabled to opt out of automatic SQL onboarding + az tag create --resource-id "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup" --tags ArcSQLServerExtensionDeployment=Disabled + $SQLvmName = "ArcBox-SQL" $SQLvmvhdPath = "$Env:ArcBoxVMDir\${SQLvmName}.vhdx" - Write-Host "Fetching Nested VMs" + Write-Host "Fetching SQL VM" # Verify if VHD files already downloaded especially when re-running this script if (!([System.IO.File]::Exists($SQLvmvhdPath) )) { @@ -195,14 +198,6 @@ if ($Env:flavor -ne "DevOps") { Write-Host "Starting SQL VM" Start-VM -Name $SQLvmName - Write-Host "Creating VM Credentials" - # Hard-coded username and password for the nested VMs - $nestedWindowsUsername = "Administrator" - $nestedWindowsPassword = "ArcDemo123!!" - - # Create Windows credential object - $secWindowsPassword = ConvertTo-SecureString $nestedWindowsPassword -AsPlainText -Force - $winCreds = New-Object System.Management.Automation.PSCredential ($nestedWindowsUsername, $secWindowsPassword) # Restarting Windows VM Network Adapters Write-Host "Restarting Network Adapters" @@ -212,14 +207,12 @@ if ($Env:flavor -ne "DevOps") { # Copy installation script to nested Windows VMs Write-Output "Transferring installation script to nested Windows VMs..." - Copy-VMFile $SQLvmName -SourcePath "$agentScript\installArcAgent.ps1" -DestinationPath "$Env:ArcBoxDir\installArcAgent.ps1" -CreateFullPath -FileSource Host -Force Copy-VMFile $SQLvmName -SourcePath "$agentScript\installArcAgentSQLSP.ps1" -DestinationPath "$Env:ArcBoxDir\installArcAgentSQL.ps1" -CreateFullPath -FileSource Host -Force Write-Header "Onboarding Arc-enabled Servers" # Onboarding the nested VMs as Azure Arc-enabled servers Write-Output "Onboarding the nested Windows VMs as Azure Arc-enabled servers" - Invoke-Command -VMName $SQLvmName -ScriptBlock { powershell -File $Using:nestedVMArcBoxDir\installArcAgent.ps1 -spnClientId $Using:spnClientId, -spnClientSecret $Using:spnClientSecret, -spnTenantId $Using:spnTenantId, -subscriptionId $Using:subscriptionId, -resourceGroup $Using:resourceGroup, -azureLocation $Using:azureLocation } -Credential $winCreds Invoke-Command -VMName $SQLvmName -ScriptBlock { powershell -File $Using:nestedVMArcBoxDir\installArcAgentSQL.ps1 -spnClientId $Using:spnClientId, -spnClientSecret $Using:spnClientSecret, -spnTenantId $Using:spnTenantId, -subscriptionId $Using:subscriptionId, -resourceGroup $Using:resourceGroup, -azureLocation $Using:azureLocation } -Credential $winCreds # Configure SSH on the nested Windows VMs @@ -229,78 +222,105 @@ if ($Env:flavor -ne "DevOps") { azcmagent config set incomingconnections.ports 22 } -Credential $winCreds + # Install Log Analytics extension to support Defender for SQL $mmaExtension = az connectedmachine extension list --machine-name $SQLvmName --resource-group $resourceGroup --query "[?name=='MicrosoftMonitoringAgent']" | ConvertFrom-Json if ($mmaExtension.Count -le 0) { # Get workspace information $workspaceID = (az monitor log-analytics workspace show --resource-group $resourceGroup --workspace-name $Env:workspaceName --query "customerId" -o tsv) $workspaceKey = (az monitor log-analytics workspace get-shared-keys --resource-group $resourceGroup --workspace-name $Env:workspaceName --query "primarySharedKey" -o tsv) + + Write-Host "Deploying Microsoft Monitoring Agent to test Defender for SQL." az connectedmachine extension create --machine-name $SQLvmName --name "MicrosoftMonitoringAgent" --settings "{'workspaceId':'$workspaceID'}" --protected-settings "{'workspaceKey':'$workspaceKey'}" --resource-group $resourceGroup --type-handler-version "1.0.18067.0" --type "MicrosoftMonitoringAgent" --publisher "Microsoft.EnterpriseCloud.Monitoring" --no-wait + Write-Host "Microsoft Monitoring Agent deployment initiated." } + # Azure Monitor Agent extension is deployed automatically using Azure Policy. Wait until extension status is Succeded. + $retryCount = 0 + do { + Start-Sleep(60) + $amaExtension = az connectedmachine extension list --machine-name $SQLvmName --resource-group $resourceGroup --query "[?name=='AzureMonitorWindowsAgent']" | ConvertFrom-Json + if ($amaExtension[0].properties.instanceView.status.code -eq 0) { + Write-Host "Azure Monitoring Agent extension installation complete." + break + } + + $retryCount = $retryCount + 1 + Write-Host "Waiting for Azure Monitoring Agent extension installation to complete ... Retry count: $retryCount" + + if ($retryCount -gt 5) { + Write-Host "WARNING: Azure Monitor Agent extenstion is taking longger than expected. Enable SQL BPA later through Azure portal." + } + + } while ($retryCount -le 5) + # Enable Best practices assessment - # Create custom log analytics table for SQL assessment - az monitor log-analytics workspace table create --resource-group $resourceGroup --workspace-name $Env:workspaceName -n SqlAssessment_CL --columns RawData=string TimeGenerated=datetime --only-show-errors - - # Verify if Arc-enabled server and SQL server extensions are installed - $ArcServer = az connectedmachine show --name $SQLvmName --resource-group $resourceGroup - if ($null -ne $ArcServer) { - $sqlExtension = az connectedmachine extension list --machine-name $SQLvmName --resource-group $resourceGroup --query "[?name=='WindowsAgent.SqlServer']" | ConvertFrom-Json - if ($null -ne $sqlExtension) { - # SQL server extension is installed and ready to run SQL BPA - Write-Host "SQL server extension is installed and ready to run SQL BPA." + if ($amaExtension[0].properties.instanceView.status.code -eq 0) { + + # Create custom log analytics table for SQL assessment + az monitor log-analytics workspace table create --resource-group $resourceGroup --workspace-name $Env:workspaceName -n SqlAssessment_CL --columns RawData=string TimeGenerated=datetime --only-show-errors + + # Verify if Arc-enabled server and SQL server extensions are installed + $ArcServer = az connectedmachine show --name $SQLvmName --resource-group $resourceGroup + if ($null -ne $ArcServer) { + $sqlExtension = az connectedmachine extension list --machine-name $SQLvmName --resource-group $resourceGroup --query "[?name=='WindowsAgent.SqlServer']" | ConvertFrom-Json + if ($null -ne $sqlExtension) { + # SQL server extension is installed and ready to run SQL BPA + Write-Host "SQL server extension is installed and ready to run SQL BPA." + } + else { + # Arc SQL Server extension is not installed or still in progress. + Write-Host "SQL server extension is not installed and can't run SQL BPA." + Exit + } } else { - # Arc SQL Server extension is not installed or still in progress. - Write-Host "SQL server extension is not installed and can't run SQL BPA." + # ArcBox-SQL Arc-enabled server resource not found + Write-Host "ArcBox-SQL Arc-enabled server resource not found. Re-run onboard script to fix this issue." Exit } - } - else { - # ArcBox-SQL Arc-enabled server resource not found - Write-Host "ArcBox-SQL Arc-enabled server resource not found. Re-run onboard script to fix this issue." - Exit - } - # Verify if ArcBox SQL resource is created - $arcSQLStatus = az resource list --resource-group $resourceGroup --query "[?name=='$SQLvmName'] | [?type=='Microsoft.AzureArcData/SqlServerInstances'].[provisioningState]" -o tsv - if ($arcSQLStatus -ne "Succeeded"){ - Write-Host "ArcBox-SQL Arc-enabled server resource not found. Wait for the resource to be created and follow troubleshooting guide to run assessment manually." - } - else { - <# Action when all if and elseif conditions are false #> - Write-Host "Enabling SQL server best practices assessment" - $bpaDeploymentTemplateUrl = "$Env:templateBaseUrl/artifacts/sqlbpa.json" - az deployment group create --resource-group $resourceGroup --template-uri $bpaDeploymentTemplateUrl --parameters workspaceName=$Env:workspaceName vmName=$SQLvmName arcSubscriptionId=$subscriptionId + + # Verify if ArcBox SQL resource is created + $arcSQLStatus = az resource list --resource-group $resourceGroup --query "[?type=='Microsoft.AzureArcData/SqlServerInstances'].[provisioningState]" -o tsv + if ($arcSQLStatus -ne "Succeeded"){ + Write-Host "WARNING: ArcBox-SQL Arc-enabled server resource not found. Wait for the resource to be created and follow troubleshooting guide to run assessment manually." + } + else { + <# Action when all if and elseif conditions are false #> + Write-Host "Enabling SQL server best practices assessment" + $bpaDeploymentTemplateUrl = "$Env:templateBaseUrl/artifacts/sqlbpa.json" + az deployment group create --resource-group $resourceGroup --template-uri $bpaDeploymentTemplateUrl --parameters workspaceName=$Env:workspaceName vmName=$SQLvmName arcSubscriptionId=$subscriptionId - # Run Best practices assessment - Write-Host "Execute SQL server best practices assessment" + # Run Best practices assessment + Write-Host "Execute SQL server best practices assessment" - # Wait for a minute to finish everyting and run assessment - Start-Sleep(60) + # Wait for a minute to finish everyting and run assessment + Start-Sleep(60) - # Get access token to make ARM REST API call for SQL server BPA - $armRestApiEndpoint = "https://management.azure.com/subscriptions/$subscriptionId/resourcegroups/$resourceGroup/providers/Microsoft.HybridCompute/machines/$SQLvmName/extensions/WindowsAgent.SqlServer?api-version=2019-08-02-preview" - $token = (az account get-access-token --subscription $subscriptionId --query accessToken --output tsv) - $headers = @{"Authorization" = "Bearer $token"; "Content-Type" = "application/json" } + # Get access token to make ARM REST API call for SQL server BPA + $armRestApiEndpoint = "https://management.azure.com/subscriptions/$subscriptionId/resourcegroups/$resourceGroup/providers/Microsoft.HybridCompute/machines/$SQLvmName/extensions/WindowsAgent.SqlServer?api-version=2019-08-02-preview" + $token = (az account get-access-token --subscription $subscriptionId --query accessToken --output tsv) + $headers = @{"Authorization" = "Bearer $token"; "Content-Type" = "application/json" } - # Build API request payload - $worspaceResourceId = "/subscriptions/$subscriptionId/resourcegroups/$resourceGroup/providers/microsoft.operationalinsights/workspaces/$Env:workspaceName".ToLower() - $sqlExtensionId = "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/providers/Microsoft.HybridCompute/machines/$SQLvmName/extensions/WindowsAgent.SqlServer" - $sqlbpaPayloadTemplate = "$Env:templateBaseUrl/artifacts/sqlbpa.payload.json" - $settingsSaveTime = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() - $apiPayload = (Invoke-WebRequest -Uri $sqlbpaPayloadTemplate).Content -replace '{{RESOURCEID}}', $sqlExtensionId -replace '{{LOCATION}}', $azureLocation -replace '{{WORKSPACEID}}', $worspaceResourceId -replace '{{SAVETIME}}', $settingsSaveTime + # Build API request payload + $worspaceResourceId = "/subscriptions/$subscriptionId/resourcegroups/$resourceGroup/providers/microsoft.operationalinsights/workspaces/$Env:workspaceName".ToLower() + $sqlExtensionId = "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup/providers/Microsoft.HybridCompute/machines/$SQLvmName/extensions/WindowsAgent.SqlServer" + $sqlbpaPayloadTemplate = "$Env:templateBaseUrl/artifacts/sqlbpa.payload.json" + $settingsSaveTime = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds() + $apiPayload = (Invoke-WebRequest -Uri $sqlbpaPayloadTemplate).Content -replace '{{RESOURCEID}}', $sqlExtensionId -replace '{{LOCATION}}', $azureLocation -replace '{{WORKSPACEID}}', $worspaceResourceId -replace '{{SAVETIME}}', $settingsSaveTime - # Call REST API to run best practices assessment - $httpResp = Invoke-WebRequest -Method Patch -Uri $armRestApiEndpoint -Body $apiPayload -Headers $headers - if (($httpResp.StatusCode -eq 200) -or ($httpResp.StatusCode -eq 202)){ - Write-Host "Arc-enabled SQL server best practices assessment executed. Wait for assessment to complete to view results." - } - else { - <# Action when all if and elseif conditions are false #> - Write-Host "SQL Best Practices Assessment faild. Please refer troubleshooting guide to run manually." + # Call REST API to run best practices assessment + $httpResp = Invoke-WebRequest -Method Patch -Uri $armRestApiEndpoint -Body $apiPayload -Headers $headers + if (($httpResp.StatusCode -eq 200) -or ($httpResp.StatusCode -eq 202)){ + Write-Host "Arc-enabled SQL server best practices assessment executed. Wait for assessment to complete to view results." + } + else { + <# Action when all if and elseif conditions are false #> + Write-Host "SQL Best Practices Assessment faild. Please refer troubleshooting guide to run manually." + } } - } + } # End of SQL BPA # Test Defender for SQL Write-Header "Simulating SQL threats to generate alerts from Defender for Cloud" diff --git a/azure_jumpstart_arcbox/artifacts/sqlbpa.json b/azure_jumpstart_arcbox/artifacts/sqlbpa.json index cc5acf8f99..840bc1f95f 100644 --- a/azure_jumpstart_arcbox/artifacts/sqlbpa.json +++ b/azure_jumpstart_arcbox/artifacts/sqlbpa.json @@ -125,17 +125,6 @@ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "resources": [ - { - "type": "Microsoft.HybridCompute/machines/extensions", - "apiVersion": "2021-12-10-preview", - "name": "[format('{0}/AzureMonitorWindowsAgent', parameters('vmName'))]", - "location": "[variables('location')]", - "properties": { - "publisher": "Microsoft.Azure.Monitor", - "type": "AzureMonitorWindowsAgent", - "autoUpgradeMinorVersion": true - } - }, { "type": "Microsoft.Insights/dataCollectionRuleAssociations", "apiVersion": "2021-09-01-preview",