This blog will show you how you can automate an overview using Kusto queries against Azure Resource Graph (ARG) to show specific resources NOT being protected by Azure backup services.
As part of Azure Backup services, Microsoft are offering 2 services which will keep your backups in a manageable vault: Azure Recovery Services Vaults and Azure Backup Vaults
Supported data sources by Azure Backups vaults:
Recovery Services Vault | Backup Vault |
Azure Virtual machines SQL in Azure VM Azure Files (Azure Storage) SAP HANA in Azure VM Azure Backup Server Azure Backup Agent DPM | Azure Disks Azure Blobs (Azure Storage) Azure Database for PostgreSQL servers Kubernetes Services (Preview) |
Of course you can choose to protect a resource by other 3rd party solutions – or you can choose not to protect it. But things can also be forgotten, if your environment is not managed through automation.
How to see resources NOT protected using the GUI?
Go into Azure Backup Center, and choose Protectable datasources – and now you can filter data source type and see resources NOT configured for backup.
How to see resources NOT protected using Kusto query?
As the data is stored inside Azure Resource Graph (ARG), you can query for the results, which means that you can use it as part of monitoring for non-protected resources.
If you continue reading, I have included modified kusto queries, which will cover 4 scenarios:
Azure VMs with no SQL databases configured for backup |
Azure Virtual machines not configured for backup |
Storage accounts with no Azure Blobs configured for backup |
Managed Kubernetes Clusters with no resources configured for backup |
Azure VMs with no SQL databases configured for backup
Resources
| where type in~ ('microsoft.compute/virtualmachines','microsoft.classiccompute/virtualmachines','microsoft.compute/virtualmachines/extensions')
| extend armResourceId = id
| where name =~ 'SqlIaasExtension'
| where properties.type == 'SqlIaaSAgent'
| extend armResourceId = split(armResourceId,'/extensions/')[0]
| extend name = split(armResourceId, '/virtualMachines/')[1]
| extend resourceId=tolower(armResourceId)
| join kind = leftouter ( RecoveryServicesResources
| where type == "microsoft.recoveryservices/vaults/backupfabrics/protectioncontainers/protecteditems"
| where properties.backupManagementType == "AzureWorkload"
| where properties.workloadType in~ ("SQLDataBase")
| project resourceId = tolower(tostring(properties.sourceResourceId)), backupItemid = id, isBackedUp = isnotempty(id) )
on resourceId
| extend isProtected = isnotempty(backupItemid) | where (isProtected == (0))
| join kind=inner (resourcecontainers
| where type == "microsoft.resources/subscriptions"
| project subscriptionId, subscriptionName=name )
on $left.subscriptionId == $right.subscriptionId
Azure Virtual machines not configured for backup
Resources
| where type in~ ('microsoft.compute/virtualmachines','microsoft.classiccompute/virtualmachines')
| extend armResourceId = id
| extend resourceId=tolower(armResourceId)
| join kind = leftouter ( RecoveryServicesResources
| where type == "microsoft.recoveryservices/vaults/backupfabrics/protectioncontainers/protecteditems"
| where properties.backupManagementType == "AzureIaasVM"
| where properties.workloadType in~ ("VM")
| project resourceId = tolower(tostring(properties.sourceResourceId)), backupItemid = id, isBackedUp = isnotempty(id) )
on resourceId
| extend isProtected = isnotempty(backupItemid)
| where (isProtected == (0))
| join kind=inner (resourcecontainers
| where type == "microsoft.resources/subscriptions"
| project subscriptionId, subscriptionName=name )
on $left.subscriptionId == $right.subscriptionId
Storage accounts with no Azure Blobs configured for backup
Resources
| where type in~ ('microsoft.storage/storageAccounts')
| extend armResourceId = id
| where properties.isHnsEnabled != true
| where properties.isNfsV3Enabled != true
| where kind =~ 'StorageV2' and isnotnull(sku) and sku.tier =~ 'Standard'
| extend resourceId=tolower(armResourceId)
| extend extendedLocationName=extendedLocation.name
| join kind = leftouter ( RecoveryServicesResources
| where type in~ ("microsoft.dataprotection/backupvaults/backupinstances", "microsoft.dataprotection/backupvaults/deletedbackupinstances")
| where properties.dataSourceInfo.datasourceType == "Microsoft.Storage/storageAccounts/blobServices"
| project resourceId = tolower(tostring(properties.dataSourceInfo.resourceID)), backupItemid = id, isBackedUp = isnotempty(id) )
on resourceId
| extend isProtected = isnotempty(backupItemid) | where (isProtected == (0))
| join kind=inner (resourcecontainers
| where type == "microsoft.resources/subscriptions"
| project subscriptionId, subscriptionName=name )
on $left.subscriptionId == $right.subscriptionId
Managed Kubernetes Clusters with no resources configured for backup
Resources
| where type in~ ('Microsoft.ContainerService/managedClusters')
| extend armResourceId = id
| extend resourceId=tolower(armResourceId)
| extend extendedLocationName=extendedLocation.name
| join kind = leftouter ( RecoveryServicesResources
| where type in~ ("microsoft.dataprotection/backupvaults/backupinstances", "microsoft.dataprotection/backupvaults/deletedbackupinstances")
| where properties.dataSourceInfo.datasourceType == "Microsoft.ContainerService/managedClusters"
| project resourceId = tolower(tostring(properties.dataSourceSetInfo.resourceID)), backupItemid = id, isBackedUp = isnotempty(id) )
on resourceId
| summarize backupInstancesCountByServer = count(isBackedUp) by resourceId, id, subscriptionId, name, resourceGroup, location, tostring(tags)
| where backupInstancesCountByServer == 0
| join kind=inner (resourcecontainers
| where type == "microsoft.resources/subscriptions"
| project subscriptionId, subscriptionName=name )
on $left.subscriptionId == $right.subscriptionId