In our integration platform we have lots of developers continually developing multiple changes concurrently across many projects. It wouldnt be too difficult to accidently delete a resource. Obviously we mitigate this risk a lot by using devops pipelines for deployments to most environments but you know that Delete button is all to easily located next to the refresh button in the Azure portal.
We can mitigate this risk further by using Azure Resource Locks. I have round that simply applying a resource group level lock can be overly prohibitive so we wanted to add delete locks to certain resources in certain environments.
If ever we need to decommission a resource then we can remove its lock and delete it nice and safely but we also would usually use privileged identity manager so you can only delete a resource by elevating your permissions with an approval step.
Add Resource Locks
The below script can be used to add resource locks. Note that it has 2 lists where we can check for resource types and specific resources we want to exclude from the locks.
$mainEnvironmentName = $env:CommonSetting_EnvironmentName_LowerCase
$mainResourceGroupName = "Mike-RG-" + $mainEnvironmentName
function ApplyResourceLock([string] $resourceGroupName, [string] $resourceType, [string]$resourceName)
{
$existingLock = Get-AzResourceLock -ResourceName $resourceName -ResourceType $resourceType -ResourceGroupName $resourceGroupName
if($existingLock -eq $null){
$newLock = New-AzResourceLock -LockLevel CanNotDelete -LockName LockSite -ResourceName $resourceName -ResourceType $resourceType -ResourceGroupName $resourceGroupName -Force
Write-Host 'New Lock Created, ID: ' $newLock.LockId -ForegroundColor Green
}
else{
Write-Host 'The Lock is already in place for resource' $resourceName ', Lock ID: ' $existingLock.LockId
}
}
Write-Host $mainEnvironmentName
Write-Host $mainResourceGroupName
$resourcesToExclude = New-Object "System.Collections.Generic.List[System.String]"
$resourcesToExclude.Add('my-resource-' + $mainEnvironmentName)
$resourcesTypesToExclude = New-Object "System.Collections.Generic.List[System.String]"
$resourcesTypesToExclude.Add('microsoft.alertsmanagement/smartdetectoralertrules')
$resourcesTypesToExclude.Add('microsoft.insights/actiongroups')
$resourcesTypesToExclude.Add('microsoft.insights/metricalerts')
$resourcesTypesToExclude.Add('microsoft.insights/workbooks')
$resources = Get-AzResource -ResourceGroupName $mainResourceGroupName
foreach($resource in $resources){
Write-Host ''
Write-Host 'Processing Resource' -ForegroundColor Green
Write-Host '===================' -ForegroundColor Green
Write-Host 'Resource: ' $resource.Name
Write-Host 'Resource Type: ' $resource.Type
#If the resource type is not in the list of resource types to ignore then we will look to lock it
if($resourcesTypesToExclude.Contains($resource.Type.ToLower()) -eq $false){
#If resource is not in the specific list to exclude then we will lock it
if($resourcesToExclude.Contains($resource.Name.ToLower()) -eq $false){
#Check that a lock is applied to the resource
ApplyResourceLock -resourceName $resource.Name -resourceType $resource.Type -resourceGroupName $mainResourceGroupName
}
else{
Write-Host 'Skipping resource as its excluded'
}
}
else{
Write-Host 'Skipping resource as its excluded'
}
}
Remove Resource Locks
For troubleshooting we want to sometimes remove all resource locks on the resource group. Normally we would remove them individually just for the resources we need to delete but in a scenario where we want to make a bunch of changes we might remove the locks with the below script.
$mainEnvironmentName = $env:CommonSetting_EnvironmentName_LowerCase
$mainResourceGroupName = "Mike-RG-" + $mainEnvironmentName
Write-Host $mainEnvironmentName
Write-Host $mainResourceGroupName
$resourceLocks = Get-AzResourceLock -ResourceGroupName $mainResourceGroupName
foreach($resourceLock in $resourceLocks){
Write-Host 'Remove: ' $resourceLock.LockId
Remove-AzResourceLock -LockId $resourceLock.LockId
}