How to fully provision AKS backups using Bicep
I have an AKS cluster which I now want to add scheduled backups to using my Bicep-based provisioning pipeline.
I haven't found much guidance for this online but I've put together the following Bicep definitions for the various components. In addition to the cluster itself this provisions a backup vault, a backup policy (to run once every evening), a storage account with container for the backups, and adds the backup extension to my cluster. I had hoped this was all I'd need, but having waiting overnight nothing has happened. No backup and no evidence of a backup even being attempted. What am I missing?
Worth noting that if I try to perform a manual backup then I see the following warnings:
- Extension MSI Role Permissions are missing for the associated storage account.
- Trusted Access and/or Role Permissions are missing for the selected cluster.
I'm given the option of adding both these manually but I want to do everything by pipeline so it's repeatable. Could someone advise what precisely I need to provision in order to clear these warnings? Is there anything else I need to get these backups working?
Thanks in advance.
var aksClusterName = '${resourcePrefix}-cluster'
resource aks 'Microsoft.ContainerService/managedClusters@2024-08-01' = {
name: aksClusterName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
dnsPrefix: useDnsPrefix
oidcIssuerProfile: {
enabled: true // Combines with securityProfile/workloadIdentity to enable workload identity
}
securityProfile: {
workloadIdentity: {
enabled: true
}
}
autoUpgradeProfile: {
upgradeChannel: 'stable'
}
agentPoolProfiles: [
{
name: 'agentpool'
osDiskSizeGB: osDiskSizeGB
count: agentCount
vmSize: agentVMSize
osType: 'Linux'
mode: 'System'
vnetSubnetID: subnetId
enableAutoScaling: true
minCount: 1
maxCount: maxNodes
}
]
linuxProfile: {
adminUsername: linuxAdminUsername
ssh: {
publicKeys: [
{
keyData: sshPublicKey
}
]
}
}
}
}
var backupVaultName = '${resourcePrefix}-backup-vault'
resource backupVault 'Microsoft.DataProtection/backupVaults@2024-04-01' = {
name: backupVaultName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
storageSettings: [
{
datastoreType: 'VaultStore'
type: 'LocallyRedundant'
}
]
monitoringSettings: {
azureMonitorAlertSettings: {
alertsForAllJobFailures: 'Enabled'
}
}
}
}
resource backupPolicy 'Microsoft.DataProtection/backupVaults/backupPolicies@2024-04-01' = {
name: 'daily'
parent: backupVault
properties: {
objectType: 'BackupPolicy'
datasourceTypes: [
'Microsoft.ContainerService/managedClusters'
]
policyRules: [
{
objectType: 'AzureRetentionRule'
name: 'Default'
isDefault: true
lifecycles: [
{
deleteAfter: {
objectType: 'AbsoluteDeleteOption'
duration: 'P7D'
}
sourceDataStore: {
objectType: 'DataStoreInfoBase'
dataStoreType: 'OperationalStore'
}
}
]
}
{
name: 'BackupDaily'
objectType: 'AzureBackupRule'
backupParameters: {
objectType: 'AzureBackupParams'
backupType: 'Incremental'
}
trigger: {
objectType: 'ScheduleBasedTriggerContext'
schedule: {
repeatingTimeIntervals: [
'R/2024-11-19T23:00:00+00:00/P1D'
]
}
taggingCriteria: [
{
tagInfo: {
tagName: 'Default'
}
taggingPriority: 99
isDefault: true
}
]
}
dataStore: {
dataStoreType: 'OperationalStore'
objectType: 'DataStoreInfoBase'
}
}
]
}
}
var backupStorageAccountName = '${resourcePrefixShort}${locationShort}bkp'
var backupContainerName = '${resourcePrefix}-${location}-cluster-backup'
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-05-01' = {
location: location
name: backupStorageAccountName
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
dependsOn: [
aks
]
}
resource storageAccountBlobService 'Microsoft.Storage/storageAccounts/blobServices@2022-05-01' = {
name: 'default'
parent: storageAccount
properties: {
lastAccessTimeTrackingPolicy: {
blobType: [
'string'
]
enable: true
name: 'AccessTimeTracking'
trackingGranularityInDays: 1
}
}
}
resource backupContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-04-01' = {
parent: storageAccountBlobService
name: backupContainerName
properties: {
publicAccess: 'None'
}
}
var backupExtensionName = '${resourcePrefixShort}${locationShort}bkpext'
resource backupExtension 'Microsoft.KubernetesConfiguration/extensions@2023-05-01' = {
name: backupExtensionName
scope: aks
properties: {
extensionType: 'microsoft.dataprotection.kubernetes'
configurationSettings: {
'configuration.backupStorageLocation.bucket': backupContainerName
'configuration.backupStorageLocation.config.storageAccount': backupStorageAccountName
'configuration.backupStorageLocation.config.resourceGroup': resourceGroup().name
'configuration.backupStorageLocation.config.subscriptionId': subscription().subscriptionId
'credentials.tenantId': subscription().tenantId
}
}
dependsOn: [
backupContainer
]
}