Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArcBox changes to address SQL BPA #1969

Merged
merged 11 commits into from
Jun 27, 2023
3 changes: 2 additions & 1 deletion azure_jumpstart_arcbox/ARM/mgmt/policyAzureArcBuiltins.json
Original file line number Diff line number Diff line change
Expand Up @@ -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')]",
Expand Down
146 changes: 83 additions & 63 deletions azure_jumpstart_arcbox/artifacts/ArcServersLogonScript.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) )) {
Expand Down Expand Up @@ -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"
Expand All @@ -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
Expand All @@ -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"
Expand Down
11 changes: 0 additions & 11 deletions azure_jumpstart_arcbox/artifacts/sqlbpa.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down