Skip to content

Commit

Permalink
Backup Azure Files to Recovery Services Vault (#142)
Browse files Browse the repository at this point in the history
* Create Backup Policy for AzFiles
* Rename protected item module
* Protect file shares with Backup
* Clarify output name of VM enhanced backup policy
  • Loading branch information
SvenAelterman authored Dec 17, 2024
1 parent dd4b9d4 commit 092cf32
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 72 deletions.
11 changes: 9 additions & 2 deletions research-spoke/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ module vdiModule '../shared-modules/virtualDesktop/main.bicep' = if (useSessionH
diskEncryptionSetId: diskEncryptionSetModule.outputs.id
sessionHostCount: sessionHostCount

backupPolicyName: recoveryServicesVaultModule.outputs.backupPolicyName
backupPolicyName: recoveryServicesVaultModule.outputs.vmBackupPolicyName
recoveryServicesVaultId: recoveryServicesVaultModule.outputs.id

// TODO: Use activeDirectoryDomainInfo type
Expand Down Expand Up @@ -649,6 +649,13 @@ module recoveryServicesVaultModule '../shared-modules/recovery/recoveryServicesV
roles: rolesModule.outputs.roles
keyVaultResourceGroupName: keyVaultModule.outputs.resourceGroupName
keyVaultName: keyVaultModule.outputs.keyVaultName

timeZone: 'Central Standard Time'

protectedStorageAccountId: storageModule.outputs.storageAccountId
protectedAzureFileShares: [
fileShareNames.shared
]
}
}

Expand All @@ -667,7 +674,7 @@ resource avdConnectionPrivateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-
}

output recoveryServicesVaultId string = recoveryServicesVaultModule.outputs.id
output backupPolicyName string = recoveryServicesVaultModule.outputs.backupPolicyName
output vmBackupPolicyName string = recoveryServicesVaultModule.outputs.vmBackupPolicyName
output diskEncryptionSetId string = diskEncryptionSetModule.outputs.id
output computeSubnetId string = networkModule.outputs.createdSubnets.computeSubnet.id
output computeResourceGroupName string = computeRg.name
Expand Down
2 changes: 1 addition & 1 deletion shared-modules/compute/virtualMachine.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ var rsvRgName = !empty(recoveryServicesVaultId) ? split(recoveryServicesVaultId,

// Create a backup item for each session host
// This must be deployed in a separate module because it's in a different resource group
module backupItems '../recovery/rsvProtectedItem.bicep' = if (!empty(backupPolicyName) && !empty(recoveryServicesVaultId)) {
module backupItems '../recovery/rsvProtectedItem-vm.bicep' = if (!empty(backupPolicyName) && !empty(recoveryServicesVaultId)) {
name: replace(deploymentNameStructure, '{rtype}', '${vmHostName}-backup')
scope: resourceGroup(rsvRgName)
params: {
Expand Down
189 changes: 120 additions & 69 deletions shared-modules/recovery/recoveryServicesVault.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,83 @@ param location string = resourceGroup().location
param tags object
param storageType string = 'GeoRedundant'

param backupTime string = '2023-12-31T08:00:00.000Z'
param dailyRetentionDurationCount int = 8
param weeklyRetentionDurationCount int = 6
param monthlyRetentionDurationCount int = 13
param weeklyRetentionDays ('Sunday' | 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday')[] = [
'Sunday'
]
param timeZone string

param protectedStorageAccountId string
param protectedAzureFileShares string[]

@description('The schedule policy used for the custom Virtual Machine backup policy.')
param schedulePolicy object = {
schedulePolicyType: 'SimpleSchedulePolicyV2'
scheduleRunFrequency: 'Hourly'
hourlySchedule: {
interval: 4
scheduleWindowStartTime: backupTime
scheduleWindowDuration: 4
}
dailySchedule: null
weeklySchedule: null
}

@description('The schedule policy used for the custom Azure File Shares backup policy.')
param fileShareSchedulePolicy object = {
schedulePolicyType: 'SimpleSchedulePolicy'
scheduleRunFrequency: 'Daily'
scheduleRunDays: null
scheduleRunTimes: [
backupTime
]
}

@description('The retention policy used for all custom backup policies.')
param retentionPolicy object = {
retentionPolicyType: 'LongTermRetentionPolicy'

dailySchedule: {
retentionTimes: [backupTime]
retentionDuration: {
count: dailyRetentionDurationCount
durationType: 'Days'
}
}

weeklySchedule: {
daysOfTheWeek: weeklyRetentionDays
retentionTimes: [backupTime]
retentionDuration: {
count: weeklyRetentionDurationCount
durationType: 'Weeks'
}
}

monthlySchedule: {
retentionScheduleFormatType: 'Daily'
retentionScheduleDaily: {
daysOfTheMonth: [
{
date: 1
isLast: false
}
]
}
retentionTimes: [backupTime]
retentionDuration: {
count: monthlyRetentionDurationCount
durationType: 'Months'
}
retentionScheduleWeekly: null
}

yearlySchedule: null
}

var vaultName = replace(namingStructure, '{rtype}', 'rsv')

resource keyVaultResourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' existing = {
Expand Down Expand Up @@ -68,7 +145,7 @@ resource recoveryServicesVault 'Microsoft.RecoveryServices/vaults@2024-04-01' =

publicNetworkAccess: 'Enabled'

// Use a customer-managed key when not debugging and when specified
// Use a customer-managed key when not debugging and when required
encryption: !debugMode && useCMK
? {
keyVaultProperties: {
Expand Down Expand Up @@ -112,9 +189,6 @@ resource backupConfig 'Microsoft.RecoveryServices/vaults/backupconfig@2024-04-01
}
}

// Create a new enhanced policy to use custom schedule
var backupTime = '2023-12-31T08:00:00.000Z'

// Break up the naming convention on the sequence placeholder to use for the backup RG name
var processNamingConventionPlaceholders = replace(
replace(
Expand All @@ -133,77 +207,54 @@ var splitNamingConvention = split(processNamingConventionPlaceholders, '{seq}')
var azureBackupRGNamePrefix = '${splitNamingConvention[0]}${sequenceFormatted}-'
var azureBackupRGNameSuffix = length(splitNamingConvention) > 1 ? splitNamingConvention[1] : ''

// LATER: Parameterize backup policy values
resource enhancedBackupPolicy 'Microsoft.RecoveryServices/vaults/backupPolicies@2024-04-01' = {
name: 'EnhancedPolicy-${workloadName}-${sequenceFormatted}'
parent: recoveryServicesVault
properties: {
backupManagementType: 'AzureIaasVM'

instantRPDetails: {
// Following the naming convention of the other resource groups
azureBackupRGNamePrefix: azureBackupRGNamePrefix
azureBackupRGNameSuffix: azureBackupRGNameSuffix
}

instantRpRetentionRangeInDays: 2
timeZone: 'Central Standard Time'
policyType: 'V2'

schedulePolicy: {
schedulePolicyType: 'SimpleSchedulePolicyV2'
scheduleRunFrequency: 'Hourly'
hourlySchedule: {
interval: 4
scheduleWindowStartTime: backupTime
scheduleWindowDuration: 4
}
dailySchedule: null
weeklySchedule: null
}
var backupPolicyCommonProperties = {
retentionPolicy: retentionPolicy
timeZone: timeZone
}

retentionPolicy: {
retentionPolicyType: 'LongTermRetentionPolicy'
var backupPolicyIaasVmProperties = {
schedulePolicy: schedulePolicy
backupManagementType: 'AzureIaasVM'
instantRpRetentionRangeInDays: 2
policyType: 'V2'
instantRPDetails: {
azureBackupRGNamePrefix: azureBackupRGNamePrefix
azureBackupRGNameSuffix: azureBackupRGNameSuffix
}
}

dailySchedule: {
retentionTimes: [backupTime]
retentionDuration: {
count: 8
durationType: 'Days'
}
}
var backupPolicyAzureStorageProperties = {
backupManagementType: 'AzureStorage'
workloadType: 'AzureFileShare'
schedulePolicy: fileShareSchedulePolicy
}

weeklySchedule: {
retentionTimes: [backupTime]
retentionDuration: {
count: 6
durationType: 'Weeks'
}
daysOfTheWeek: ['Sunday']
}
// Create an enhanced VM backup policy to backup multiple times per day
resource iaasVmBackupPolicy 'Microsoft.RecoveryServices/vaults/backupPolicies@2024-04-01' = {
name: 'EnhancedPolicy-${workloadName}-${sequenceFormatted}'
parent: recoveryServicesVault
properties: union(backupPolicyCommonProperties, backupPolicyIaasVmProperties)
}

monthlySchedule: {
retentionTimes: [backupTime]
retentionDuration: {
count: 13
durationType: 'Months'
}
retentionScheduleFormatType: 'Daily'
retentionScheduleDaily: {
daysOfTheMonth: [
{
date: 1
isLast: false
}
]
}
retentionScheduleWeekly: null
}
// Create a single Azure File backup policy, even if there are multiple file shares or storage accounts
resource filesBackupPolicy 'Microsoft.RecoveryServices/vaults/backupPolicies@2024-04-01' = if (length(protectedAzureFileShares) > 0) {
name: 'AzureFileSharesPolicy-${workloadName}-${sequenceFormatted}'
parent: recoveryServicesVault
properties: union(backupPolicyCommonProperties, backupPolicyAzureStorageProperties)
}

yearlySchedule: null
// Create a protected item per Azure File Share to be protected
module fileShareProtectedItems 'rsvProtectedItem-fs.bicep' = [
for fileShare in protectedAzureFileShares: {
name: take(replace(deploymentNameStructure, '{rtype}', 'rsv-fs-${fileShare}'), 64)
params: {
backupPolicyName: filesBackupPolicy.name
fileShareName: fileShare
recoveryServicesVaultId: recoveryServicesVault.id
storageAccountId: protectedStorageAccountId
}
}
}
]

// Lock the Recovery Services Vault to prevent accidental deletion
resource lock 'Microsoft.Authorization/locks@2020-05-01' = if (!debugMode) {
Expand All @@ -216,7 +267,7 @@ resource lock 'Microsoft.Authorization/locks@2020-05-01' = if (!debugMode) {

output id string = recoveryServicesVault.id
output name string = recoveryServicesVault.name
output backupPolicyName string = enhancedBackupPolicy.name
output vmBackupPolicyName string = iaasVmBackupPolicy.name

// For debug purposes only
output backupResourceGroupNameStructure string = '${azureBackupRGNamePrefix}{N}${azureBackupRGNameSuffix}'
29 changes: 29 additions & 0 deletions shared-modules/recovery/rsvProtectedItem-fs.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
param backupPolicyName string
param recoveryServicesVaultId string
param storageAccountId string
param fileShareName string

var rsvName = split(recoveryServicesVaultId, '/')[8]

var storageAccountRgName = split(storageAccountId, '/')[4]
var storageAccountName = split(storageAccountId, '/')[8]

resource protectionContainer 'Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers@2024-04-01' = {
name: '${rsvName}/Azure/storagecontainer;Storage;${storageAccountRgName};${storageAccountName}'
properties: {
backupManagementType: 'AzureStorage'
containerType: 'StorageContainer'
sourceResourceId: storageAccountId
}
}

resource protectedItem 'Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems@2024-04-01' = {
parent: protectionContainer
name: 'AzureFileShare;${fileShareName}'
properties: {
protectedItemType: 'AzureFileShareProtectedItem'
sourceResourceId: storageAccountId
policyId: resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', rsvName, backupPolicyName)
//isInlineInquiry: true
}
}

0 comments on commit 092cf32

Please sign in to comment.