How to fully provision AKS backups using Bicep

Tom Troughton 0 Reputation points
2024-11-21T19:11:52.1933333+00:00

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
  ]
}

Azure Backup
Azure Backup
An Azure backup service that provides built-in management at scale.
1,372 questions
Azure Kubernetes Service (AKS)
Azure Kubernetes Service (AKS)
An Azure service that provides serverless Kubernetes, an integrated continuous integration and continuous delivery experience, and enterprise-grade security and governance.
2,281 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Pranay Reddy Madireddy 2,170 Reputation points Microsoft Vendor
    2024-11-22T21:45:40.95+00:00

    Hi Tom Troughton

    Welcome to the Microsoft Q&A Platform! Thank you for asking your question here.

    This warning means the backup extension doesn't have permission to use the storage account for saving backups. You've mentioned that you've already fixed this issue by adding the trustedAccessRoleBindings resource, which is great.

    To fix the warning, you need to give the backup extension the right permissions to access the storage account. You can do this by adding a role in your Bicep template.

    Add this to your Bicep file to give the backup extension's MSI the Storage Blob Data Contributor role:

    resource storageAccountRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {

    name: newGuid() // Generate a new GUID for the role assignment

    scope: storageAccount // The scope is set to the storage account

    properties: {

    principalId: backupExtension.identity.principalId // Reference the principal ID of the backup extension
    
    roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', 'b9d3b4c5-8e3b-4f54-bc5f-5f9d5b1e7a9e') // Storage Blob Data Contributor role ID
    

    }

    }
    https://learn.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments?pivots=deployment-language-bicep

    If you have any further queries, do let us know.


    If the answer is helpful, please click "Accept Answer" and "Upvote it".

    0 comments No comments

  2. Jean-Pierre Fouche 0 Reputation points
    2025-02-25T12:10:00.4033333+00:00

    Have you configured a backup instance?

    See this terraform example for the general idea: https://learn.microsoft.com/en-us/azure/backup/quick-kubernetes-backup-terraform (You can implement similar in bicep)

    When you get the answer, please post here :)

    Many Thanks

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.