Automating Azure Resource Locks
Locks can be used to prevent accidental deletion of Azure Resources. But what happens when you remove a lock to perform maintenance and forget to reapply it? Azure Automation and PowerShell can be used to make sure locks are reapplied.
For an introduction to Azure Locks, check out my previous post on Azure Resource Locks
If you have a no-delete Lock in place on a Resource Group but need to delete a resource from within it, it’s necessary to remove the lock. Usually, when that maintenance is completed, the lock would be reinstated but it’s easy enough to forget that step and leave the Resource Group unprotected. A simple PowerShell Runbook in an Azure Automation account can remedy this by checking for Resource Groups that are missing locks and reapplying them.
Workflow
While Locks can be applied at the individual Resource level, or across a whole Subscription, in this example we will use Locks at the Resource Group level. In this example environment, when a new resource group is created and populated a Lock should be applied as well to protect the new resources. This lock would stay in place until a particular piece of work requires the lock to be removed.
Once this work is complete we would expect the operator to reapply the lock so protection can resume, but that step may get accidentally omitted. This is where our weekly automated process will come in. The script looks for unlocked Resource Groups. It then checks if that resource group has been unlocked for more than a week- if it’s been recently unlocked it assumes that maintenance is still ongoing so a replacement Lock does not want to be applied at this point. Finally a DoNotDelete lock is applied to those Resource Groups that are missing a lock and haven’t had one removed in the past week.
To make the operations team aware that these locks have been applied, the automated process can fire off an informational alert, for example to a specific Teams channel.
PowerShell
Check all Resource Groups tagged Production
1ForEach ($ResourceGroup In (Get-AzResourceGroup -Tag @{ "Environment"="Production"} )) {
Get the locks on the Resource Group
1$lock=Get-AZresourceLock -ResourceGroupName $ResourceGroup.ResourceGroupName | `
2 Where-Object {$_.ResourceType -eq "Microsoft.Authorization/locks"}
If a Lock is present- report this and move on. Take no further action.
1If ($lock) {
2 $ResourceGroup.ResourceGroupName+" is locked"
If a Lock is not present, we need to check if there’s an event in the activity log corresponding to a lock being removed in the past 7 days
1} else {
2 $ResourceGroup.ResourceGroupName+" is NOT locked"
3 $DaysAgo=7
4 $LogEntry=Get-AzActivityLog -ResourceGroupName $ResourceGroup.ResourceGroupName `
5 -StartTime (get-date).AddDays(-$DaysAgo) -WarningAction SilentlyContinue |
6 Where-Object {$_.Properties.Content["message"] -eq "Microsoft.Authorization/locks/delete" -and !($_.ResourceType) } |
7 Sort-Object -Property EventTimestamp -Bottom 1
If there is a modification in the past 7 days work may still be in progress so no action is taken.
1If ($LogEntry) {
2 " A lock was removed from this resource group by "+$LogEntry.Caller+" at "+ $LogEntry.EventTimestamp
However, if there is no relevant activity then the lock needs to be reapplied
1} else {
2 " Applying Missing Lock"
3 $LockNotes="Automatic Lock Applied "+(get-date -Format("yyyy-MM-dd"))
4 New-AzResourceLock -LockName "DoNotDelete" -LockLevel CanNotDelete `
5 -LockNotes $LockNotes -ResourceGroupName $ResourceGroup.ResourceGroupName
6 }
7 }
8}
Automation
With the code complete and tested it can then be inserted into a Runbook and scheduled to run using an Azure Automation account. That schedule would depend on how agressively you want to reapply missing locks, a weekly timeslot may suffice.
The last piece of this automation is to record the checks, and in particular changes, that have been made. This could take the form of a message written to an activity log, or a message pushed to the operations team via email or Teams.