diff --git a/Powershell scripts/Enable Defender for SQL servers on machines/EnableDefenderForSqlOnMachines.ps1 b/Powershell scripts/Enable Defender for SQL servers on machines/EnableDefenderForSqlOnMachines.ps1 new file mode 100644 index 000000000..9b5916063 --- /dev/null +++ b/Powershell scripts/Enable Defender for SQL servers on machines/EnableDefenderForSqlOnMachines.ps1 @@ -0,0 +1,243 @@ +<# +.SYNOPSIS +Enable Defender for SQL servers on machines. + +.DESCRIPTION +This script enables Defender for SQL servers on machines at a subscription level. + +.PARAMETER SubscriptionId +[Required] The Azure subscription ID. + +.PARAMETER RegisterSqlVmAgnet +[Required] A flag indicating whether to register the SQL VM Agent in bulk. For more information: https://learn.microsoft.com/en-us/azure/azure-sql/virtual-machines/windows/sql-agent-extension-manually-register-vms-bulk?view=azuresql + +.PARAMETER WorkspaceResourceId +[Optional] The resource ID of the Log Analytics workspace, if you want to use a custom one and not the default one. + +.PARAMETER DataCollectionRuleResourceId +[Optional] The resource ID of the data collection rule, if you want to use a custom one and not the default one. + +.PARAMETER UserAssignedIdentityResourceId +[Optional] The resource ID of the user-assigned identity, if you want to use a custom one and not the default one. +#> + +param( + [Parameter(Mandatory=$true)] + [string]$SubscriptionId, + [Parameter(Mandatory=$true)] + [bool]$RegisterSqlVmAgnet, + [string]$WorkspaceResourceId, + [string]$DataCollectionRuleResourceId, + [string]$UserAssignedIdentityResourceId +) + +$policyDefinitionReferenceIdsDefault = @( + "MDC_DfSQL_AddUserAssignedIdentity_VM", + "MDC_DfSQL_DeployWindowsAMA_VM", + "MDC_DfSQL_DeployMicrosoftDefenderForSQLWindowsAgent_VM", + "MDC_DfSQL_DeployDefaultWorkspace", + "MDC_DfSQL_AMA_DefaultPipeline_VM", + "MDC_DfSQL_DeployWindowsAMA_Arc", + "MDC_DfSQL_DeployMicrosoftDefenderForSQLWindowsAgent_Arc", + "MDC_DfSQL_AMA_DefaultPipeline_Arc", + "MDC_DfSQL_AMA_DefaultPipeline_DCRA_Arc" +) + +$policyDefinitionReferenceIdsCustom = @( + "MDC_DfSQL_AddUserAssignedIdentity_VM", + "MDC_DfSQL_DeployWindowsAMA_VM", + "MDC_DfSQL_DeployMicrosoftDefenderForSQLWindowsAgent_VM", + "MDC_DfSQL_AMA_UserWorkspacePipeline_VM", + "MDC_DfSQL_DeployWindowsAMA_Arc", + "MDC_DfSQL_DeployMicrosoftDefenderForSQLWindowsAgent_Arc", + "MDC_DfSQL_AMA_UserWorkspacePipeline_Arc", + "MDC_DfSQL_AMA_UserWorkspacePipeline_DCRA_Arc" +) + +$policyInitiativeNames = @{ + "default" = "d7c3ea3a-edf3-4bd5-bd64-d5b635b05393" + "custom" = "de01d381-bae9-4670-8870-786f89f49e26" +} + +$defaultLocation = "eastus" + +# Function to assign policy initiative definition with parameters +function AssignPolicyInitiative { + param( + [Parameter(Mandatory=$true)] + [string]$SubscriptionId, + [Parameter(Mandatory=$true)] + [string]$PolicyInitiativeName, + [Parameter(Mandatory=$true)] + [string]$AssignmentName, + [string]$WorkspaceResourceId + ) + + $policySetDefinition = Get-AzPolicySetDefinition -Name $PolicyInitiativeName + + if($AssignmentName.Length -gt 63) { + $AssignmentName = $AssignmentName.Substring(0, 63) + } + + # Assign policy initiative definition + $assignmentParams = @{ + "PolicySetDefinition" = $policySetDefinition + "Name" = $AssignmentName + "PolicyParameterObject" = @{} + } + + if ($WorkspaceResourceId) { + if ($WorkspaceResourceId.StartsWith("/")) { + $WorkspaceResourceId = $WorkspaceResourceId.Substring(1) + } + + # Get the Log Analytics workspace + $workspace = Get-AzOperationalInsightsWorkspace -ResourceGroupName ($WorkspaceResourceId -split '/')[3] -Name ($WorkspaceResourceId -split '/')[7] + + $assignmentParams["PolicyParameterObject"]["userWorkspaceResourceId"] = "/" + $WorkspaceResourceId + $assignmentParams["PolicyParameterObject"]["workspaceRegion"] = $workspace.Location + $assignmentParams["PolicyParameterObject"]["userWorkspaceId"] = $workspace.CustomerId + + if ($DataCollectionRuleResourceId) { + $assignmentParams["PolicyParameterObject"]["bringYourOwnDcr"] = $true + $assignmentParams["PolicyParameterObject"]["dcrResourceId"] = $DataCollectionRuleResourceId + } + } + + if ($UserAssignedIdentityResourceId) { + $assignmentParams["PolicyParameterObject"]["bringYourOwnUserAssignedManagedIdentity"] = $true + $assignmentParams["PolicyParameterObject"]["userAssignedIdentityResourceId"] = $UserAssignedIdentityResourceId + } + + return New-AzPolicyAssignment @assignmentParams -Scope "/subscriptions/$SubscriptionId" -IdentityType "SystemAssigned" -Location $defaultLocation +} + +# Main script + +try +{ + Write-Host "Connecting to Azure..." + Connect-AzAccount -ErrorAction Stop + + # Azure subscription ID + $subscriptionId = $SubscriptionId + + Write-Host "Selecting Azure subscription $subscriptionId..." + # Select the subscription + Select-AzSubscription -SubscriptionId $subscriptionId -ErrorAction Stop + + # SQL VM bulk registration + $bulkRegistration = $RegisterSqlVmAgnet + + $policyDefinitionReferenceIds = $policyDefinitionReferenceIdsDefault + $policyAssignmentName = "Defender for SQL on SQL VMs and Arc-enabled SQL Servers" + + $policyAssignment = @{} + + Write-Host "Assigning policy initiative definition with parameters..." + + # Assign policy initiative definition with parameters + if ($WorkspaceResourceId) { + $policyAssignmentName = "Defender for SQL on SQL VMs and Arc-enabled SQL Servers- Custom" + + $policyAssignment = AssignPolicyInitiative -SubscriptionId $subscriptionId -PolicyInitiativeName $policyInitiativeNames["custom"] -AssignmentName $policyAssignmentName -WorkspaceResourceId $WorkspaceResourceId + $policyDefinitionReferenceIds = $policyDefinitionReferenceIdsCustom + } + else { + $policyAssignment = AssignPolicyInitiative -SubscriptionId $subscriptionId -PolicyInitiativeName $policyInitiativeNames["default"] -AssignmentName $policyAssignmentName + } + + # Create custom role assignments + $permissions = @( + "94877a25-7520-40c5-9c42-68e02e4758bd", # Resource Group Contributor + "e40ec5ca-96e0-45a2-b4ff-59039f2c2b59", # Managed Identity Contributor + "f1a07417-d97a-45cb-824c-7a7467783830", # Managed Identity Operator + "92aaf0da-9dab-42b6-94a3-d43ce8d16293", # Log Analytics Contributor + "9980e02c-c2be-4d73-94e8-173b1dc7cf3c", # Virtual Machine Contributor + "749f88d5-cbae-40b8-bcfc-e573ddc772fa", # Monitoring Contributor + "cd570a14-e51a-42ad-bac8-bafd67325302" # Azure Connected Machine Resource Administrator + ) + + Write-Host "Setting role assignment to policy assignment's Managed Identity..." + + # Set role assignment to policy assignment's Managed Identity + $permissions | Foreach-Object -Parallel { + try { + New-AzRoleAssignment -ObjectId $using:policyAssignment.Identity.PrincipalId -RoleDefinitionId $_ -Scope "/subscriptions/$using:subscriptionId" + } + catch { + Write-Host "Failed to assign role $_ to policy assignment's Managed Identity on subscription level." + throw $_.Exception.Message + } + } + + if($WorkspaceResourceId) { + $permissions | Foreach-Object -Parallel { + try { + New-AzRoleAssignment -ObjectId $using:policyAssignment.Identity.PrincipalId -RoleDefinitionId $_ -Scope $using:WorkspaceResourceId + } + catch { + Write-Host "Failed to assign role $_ to policy assignment's Managed Identity on workspace level." + throw $_.Exception.Message + } + } + } + + # Create and run remediation step + Write-Host "Creating and running remediation steps..." + $remediationSuccess = $true + $exceptionMessage = "" + $policyDefinitionReferenceIds | Foreach-Object -Parallel { + try { + $remediationParams = @{ + "PolicyAssignmentId" = $using:policyAssignment.PolicyAssignmentId + "Name" = "Remediation-$_" + "Scope" = "/subscriptions/$using:subscriptionId" + "ResourceDiscoveryMode" = "ReEvaluateCompliance" + "PolicyDefinitionReferenceId" = $_ + } + + # Run remediation step + Start-AzPolicyRemediation @remediationParams + } + catch { + Write-Host "Failed to create and run remediation step for policy assignment $policyAssignmentName. Exception: $($_.Exception.Message)" + $remediationSuccess = $false + $exceptionMessage = $_.Exception.Message + } + } + + if($remediationSuccess) { + Write-Host "Remediation steps created and executed successfully." + } + else { + Write-Host "Failed to create and run remediation steps for policy assignment $policyAssignmentName. Exception: $exceptionMessage" + throw $exceptionMessage + } + + # Register SQL VMs for bulk registration / sql vm checkbox + if ($bulkRegistration) { + Write-Host "Registering SQL VMs for bulk registration..." + try { + $apiUrl = "https://management.azure.com/subscriptions/$subscriptionId/providers/Microsoft.Features/providers/Microsoft.SqlVirtualMachine/features/BulkRegistration/register?api-version=2021-07-01" + $accessToken = Get-AzAccessToken + + Invoke-RestMethod -Uri $apiUrl -Method Post -Headers @{"Authorization" = "Bearer $($accessToken.Token)"} + } + catch { + Write-Host "Failed to register SQL VMs for bulk registration. Exception: $($_.Exception.Message)" + throw $_.Exception.Message + } + } + else { + Write-Host "SQL VMs will not be registered for bulk registration." + } + + # Turn on pricing bundle + Write-Host "Turning on the pricing bundle..." + Select-AzSubscription -SubscriptionId $subscriptionId + Set-AzSecurityPricing -Name SqlServerVirtualMachines -PricingTier Standard +} +catch { + Write-Host "Failed to enable SQL ATP on-premises in scale. Exception: $($_.Exception.Message)" +} \ No newline at end of file