Automate the locking of Azure resource groups

When it comes to the day to day administration of Azure resources I always do it with an extra touch of caution. And for the most part my cautious approach has paid off and I can say that I have never accidentally deleted resources that should not have been deleted. I have had one near miss though and was it not for a resource lock it might have been a very uncomfortable conversation with a manager. To ensure that my teammates and I do not land in the proverbial hot soup I have created this automation script. The script enumerates all the subscriptions the running context have access to and then loop through each subscription and enumerate the resource groups in that subscription and then loops through the resource groups and set a CannotDelete lock on each resource group.

So what are resource groups?

Resource lock helps you prevent unexpected changes. There are two levels of resource locks:

  • CannotDelete. Personally, I use this type of lock the most. Basically, when you set this type of lock on a resource you are able to change and update the properties of the resource but you are unable to delete the resource without removing the lock.
  • RealOnly. This type of lock, if implemented will restrict all change to the resource. This is useful if you would like to ensure that there are no configuration drift on resources

Lock inheritance is something to keep in mind. Locks can be implemented at a subscription level, resource group level and at a resource level. When set at a resource level only the resource that has the lock set is effected. If set at a resource group level all resources in the resource group will inherit the lock. and if set at a subscription level all the resource groups and the resources they contain will inherit the lock.

Automating the locking process

The script below can be used as a runbook in an Azure Automation account and scheduled to run the script on a daily basis to go through and ensure that the resource groups have a resource lock set on them. The script uses the AZ module which means that you will need to ensure that the correct modules are running on our automation account. Follow this link to get your storage account working with the AZ Modules

     Create resource locks for resource groups in a given subscription  

    Enumirates all subscriptions then filters by the qualifying criteria and then enumirates through the resource group in that
    subascription and set as canotdelete level lock on the resource group level. the script requires the user context to have
    owner RBAC rights on the subscription level to be able to set the resource group lock.



    In my case i have subscriptions with the "Prod" in the name of the subscription and would like to ensure that all the resource 
    groups in that "prod" subscription has a CanNotDelete lock set on the resource group.



#region parameters

#regionend parameters
#$ErrorActionPreference = "Stop"

#region variables
$context = Get-AzContext
if ($null -eq $context.Account ) {
    # Get the connection "AzureRunAsConnection"
    $connectionName = "AzureRunAsConnection"
    $servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
    $logonAttempt = 0
    $logonResult = $False
    while(!($connectionResult) -And ($logonAttempt -le 10))
        # Logging in to Azure...
        $connectionResult = Connect-AzAccount -ServicePrincipal -TenantId $servicePrincipalConnection.TenantId -ApplicationId $servicePrincipalConnection.ApplicationId -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint

Start-Sleep -Seconds 30

#Criteria used when filtering subscription names
$subscriptionNameLike = "*pass*"
#endregion variables

#region Functions
function lockResourceGroups {
    # Get array of all subscriptions
    $subscriptions = Get-AzSubscription 
    #loops through every subscription in the array
    foreach ($subscription in $subscriptions) {
        #filters subscription by name 
        if ($ -like $subscriptionNameLike) {
            Write-Host $subscription.Name
            Select-AzSubscription -SubscriptionObject $subscription
            #Construct array of resource group in the subscription
            $resourceGroups = Get-AzResourceGroup
            #loops through the resource groups and sets the resource lock on each resource group 
            foreach ($resourceGroup in $resourceGroups) {
                Write-Host "Processing: " $resourceGroup.ResourceGroupName -ForegroundColor Yellow
                #$resourceLockStatus = Get-AzResourceLock -ResourceGroupName $resourceGroup.ResourceGroupName
                Set-AzResourceLock -LockName "Delete" -LockLevel CanNotDelete -LockNotes "Contains ressources that should not be deleted" -ResourceGroupName $resourceGroup.ResourceGroupName -Force
                Write-Host $resourceGroup.ResourceGroupName "now has a lock set" -ForegroundColor Green
            #Get-AzResourceGroup | Set-AzResourceLock -LockLevel CanNotDelete -LockNotes "Updated note" -LockName "ContosoSiteLock" -ResourceName "ContosoSite" -ResourceType "microsoft.web/sites" -ResourceGroupName "ResourceGroup11"
#endregion Functions

#region script main
    #Execute the function 

#endregion script main


Happy Automating!!