Azure Blob Storage is an essential service for storing unstructured data in the cloud, with a wide range of use cases like serving images, documents, and logs. Ensuring the availability and durability of this data is a top priority. In this blog post, we will explore how to create a reusable Terraform module to backup Azure Blob Storage using azurerm_data_protection_backup_vault and private endpoints. Before diving into the Terraform configuration, let's understand the differences between various Azure backup services, terms, and definitions.

Azure Backup Vault

Understanding Azure Recovery Services, Backup Vault, and Site Recovery

Azure Recovery Services is Microsoft Azure's primary business continuity and disaster recovery (BCDR) solution. The service has two principal features: Azure Backup and Azure Site Recovery. The corresponding Azure Recovery Services vault is the storage entity that holds the data for these two services.

Azure Site Recovery (ASR) is a replication/disaster recovery engine that enables you to replicate entire workloads between your on-premises and Azure environments. Recovery Services vaults support both Hyper-V and VMware virtualization environments. You can use them to protect physical servers on-premises in addition to your virtual machines.

On the other hand, Azure Backup enables you to back up and restore Windows Server and Linux servers in Azure, on-premises, or in other clouds. Microsoft recently introduced new workloads for Azure Backup stored in the Azure Backup vault. The Backup vault is a leaner product than the Recovery Services vault (for which  we configured Azure Recovery Services Vault Terraform module in one of the previous articles) and has a more specialized set of supported workloads, protecting only selected Azure resources such as Azure VM disks, Azure Blob Storage in general-purpose storage accounts, and Azure Database for PostgreSQL servers.

It is important to note that there might be confusion around the naming conventions for these services. The term "Azure Backup" is often mistakenly associated with the Azure Backup vault, whereas it is actually related to the Recovery Services vault. Microsoft's product naming can be confusing at times, but it is crucial to differentiate these services and their supported workloads to make the best use of Azure's BCDR solutions.

In this tutorial, we will:

  1. Create a reusable Terraform module for Azure Backup Vault using azurerm_data_protection_backup_vault Terraform resource block
  2. Configure backup policies using azurerm_data_protection_backup_policy_blob_storage Terraform resource block
  3. Set up private endpoints for the Azure Backup Vault

Prerequisites for Azure Backup Vault Terraform Module

To follow this tutorial, you will need:

  1. Terraform (version 1.5.* or later)
  2. An Azure subscription
  3. The Azure CLI (version  2.48 or later)

Step 1: Create a reusable Terraform module for Azure Backup Vault using azurerm_data_protection_backup_vault 

First, let's create a reusable Terraform module for the Azure Backup Vault. This will allow us to manage the Backup Vault more efficiently. Create a new directory named 'modules' and inside that, create another directory named 'azure_backup_vault':

mkdir -p modules/azure_backup_vault

Inside the 'azure_backup_vault' directory, create separate files for variables, main, outputs, and data. Name these files 'variables.tf', 'main.tf', 'outputs.tf', and 'data.tf', respectively.

In 'variables.tf', define the input variables for the module:


variable "resource_group_name" {
  description = "The name of the Azure Resource Group."
  type        = string
}

variable "location" {
  description = "The Azure location where the resources will be created."
  type        = string
}

variable "vault_name" {
  description = "The name of the Azure Data Protection Backup Vault."
  type        = string
}

variable "backup_policy_name" {
  description = "The name of the Azure Data Protection Backup Policy for Blob Storage."
  type        = string
}

variable "private_endpoint_name" {
  description = "The name of the Azure Private Endpoint for the Backup Vault."
  type        = string
}

variable "private_service_connection_name" {
  description = "The name of the private service connection for the Backup Vault."
  type        = string
}

In this variables.tf file, we have six variable blocks:

  1. resource_group_name: This variable holds the name of the Azure Resource Group.
  2. location: This variable holds the Azure location where the resources will be created.
  3. vault_name: This variable holds the name of the Azure Data Protection Backup Vault.
  4. backup_policy_name: This variable holds the name of the Azure Data Protection Backup Policy for Blob Storage.
  5. private_endpoint_name: This variable holds the name of the Azure Private Endpoint for the Backup Vault.
  6. private_service_connection_name: This variable holds the name of the private service connection for the Backup Vault.

These variables make it easy to customize your Terraform configurations by providing values when running terraform apply. You can supply the variable values either by using the -var option when running Terraform commands or by creating a terraform.tfvars file with the variable values.

In 'main.tf', create the resources for the backup vault, backup policy, and private endpoint:

 
resource "azurerm_data_protection_backup_vault" "this" {
  name                = "example-backup-vault"
  resource_group_name = azurerm_resource_group.this.name
  location            = azurerm_resource_group.this.location
  storage_settings {
    data_store_type = "VaultStore"
    type            = "LocallyRedundant"
  }
}

resource "azurerm_data_protection_backup_policy_blob_storage" "this" {
  name     = var.policy_name
  vault_id = azurerm_data_protection_backup_vault.this.id
  retention_duration = "P30D"
  }
}

resource "azurerm_private_endpoint" "this" {
  name                = var.private_endpoint_name
  location            = var.location
  resource_group_name = var.resource_group_name
  subnet_id           = var.subnet_id

  private_service_connection {
    name                           = "${var.private_endpoint_name}_psc"
    private_connection_resource_id = azurerm_data_protection_backup_vault.this.id
    subresource_names              = ["vault"]
    is_manual_connection           = false
  }
}

resource "azurerm_private_dns_zone_group" "this" {
  name                = "${var.private_endpoint_name}_zone_group"
  private_endpoint_id = azurerm_private_endpoint.this.id
  private_dns_zone {
    name = "privatelink.backup.windowsazure.com"
  }
}

In this main.tf file, we have three resource blocks:

  1. The first block creates an Azure resource group with the specified name and location.
  2. The second block creates an Azure Data Protection Backup Vault using azurerm_data_protection_backup_vault Terraform resource. It uses the name and location of the resource group created in the first block. The storage settings specify the data_store_type as "VaultStore" and the type as "LocallyRedundant" for redundancy within the same region.
  3. The third block creates an Azure Data Protection Backup Policy for Blob Storage. It refers to the backup vault created in the second block using its ID. The retention_duration is set to "P30D", which means the backups will be retained for 30 days.
  4. The fourth block creates an Azure Private Endpoint for the Backup Vault. It uses the location and resource group name from the first block, and the subnet ID from the data.azurerm_subnet.example data block. The private_service_connection block establishes the connection to the Backup Vault using its ID, specifies the subresource name as "vault", and sets is_manual_connection to false for automatic approval of the connection.

In 'data.tf', fetch the existing networking resources for the private endpoint:

# This data block retrieves information about the existing virtual network
data "azurerm_virtual_network" "example" {
  name                = "your_virtual_network_name"
  resource_group_name = "your_resource_group_name"
}

# This data block retrieves information about the existing subnet within the virtual network
data "azurerm_subnet" "example" {
  name                 = "your_subnet_name"
  virtual_network_name = data.azurerm_virtual_network.example.name
  resource_group_name  = data.azurerm_virtual_network.example.resource_group_name
}

In this data.tf file, we are using three data blocks to fetch information about existing Azure resources. The first block retrieves information about an existing virtual network by specifying the virtual network name and the resource group name. The second block retrieves information about a subnet within the virtual network using the name of the subnet and the details of the virtual network fetched in the previous block. Please replace your_virtual_network_name, your_resource_group_name, your_subnet_name, and your_network_security_group_name with the actual names of your resources.

In 'outputs.tf', define the output variables for the module:

 
output "backup_vault_id" {
  value       = azurerm_data_protection_backup_vault.this.id
  description = "The ID of the Azure Data Protection Backup Vault."
}

output "backup_vault_name" {
  value       = azurerm_data_protection_backup_vault.this.name
  description = "The name of the Azure Data Protection Backup Vault."
}

output "backup_vault_resource_group_name" {
  value       = azurerm_data_protection_backup_vault.this.resource_group_name
  description = "The name of the resource group the Azure Data Protection Backup Vault is associated with."
}

output "backup_vault_location" {
  value       = azurerm_data_protection_backup_vault.this.location
  description = "The location of the Azure Data Protection Backup Vault."
}

output "backup_policy_id" {
  value       = azurerm_data_protection_backup_policy_blob_storage.backup_policy.id
  description = "The ID of the Azure Data Protection Backup Policy for Blob Storage."
}

output "backup_policy_name" {
  value       = azurerm_data_protection_backup_policy_blob_storage.backup_policy.name
  description = "The name of the Azure Data Protection Backup Policy for Blob Storage."
}

output "backup_policy_retention_duration" {
  value       = azurerm_data_protection_backup_policy_blob_storage.backup_policy.retention_duration
  description = "The retention duration of the Azure Data Protection Backup Policy for Blob Storage."
}

This outputs.tf file defines the outputs for the backup vault and backup policy, including their IDs, names, location, and retention duration.

Conclusion

In this tutorial, we have created a reusable Terraform module for Azure Backup Vault, configured backup policies using azurerm_data_protection_backup_policy_blob_storage, and set up private endpoints for the backup vault. This module simplifies the process of managing Azure Blob Storage backups and provides a consistent method for deploying backup infrastructure across multiple environments. Understanding the differences between Azure Recovery Services, Backup Vault, and Site Recovery, and their supported workloads will help you choose the right BCDR solution for your needs.

Reference:

Azure Backup vault:  https://learn.microsoft.com/en-us/azure/backup/backup-vault-overview 

Azure Recovery Services Vault: https://learn.microsoft.com/en-us/azure/backup/backup-azure-recovery-services-vault-overview