Skip to content

Workload Backup (SQL / SAP HANA)

Overview

Azure VM Workload Backup protects database workloads running inside a VM — primarily SQL Server in Azure VM and SAP HANA in Azure VM. It is distinct from VM-level backup (VM Backup) in that it uses application-aware backup operations (Full / Differential / Incremental / Log) instead of crash-consistent disk snapshots. A single workload policy bundles multiple protection policies (e.g. a daily Full plus an hourly Log) under one logical schedule.

The backup_policy_vm_workload module declares these policies; protected-item registration (attaching a specific database to a policy) is not yet implemented in this repository — that step is done out-of-band in the Azure portal or via the workload extension once the policy exists.

Module Structure

Module Azure Resource Purpose
backup_policy_vm_workload azurerm_backup_policy_vm_workload Workload-aware backup policy (SQL / SAP HANA), nested under a Recovery Services Vault

The module reads directly from the recovery_services_vault root variable — there is no separate top-level variable for workload policies.

Architecture

  1. Recovery Services Vault owns the policy — see Backup Overview.
  2. Workload policies are declared inside a vault under backup_policy_vm_workload = { ... }. Each entry produces one azurerm_backup_policy_vm_workload resource.
  3. Protection policies are nested under each workload policy — one per backup type (Full, Differential, Incremental, Log). Each carries its own schedule and retention.
  4. Composite key <vault_key>.<policy_key> identifies a workload policy across vaults (same convention as standard VM backup policies — see Composite Keys).

Usage

1. Declare a Workload Policy Under a Vault

recovery_services_vault = {
  epic = {
    resource_group    = "recoveryvault"
    storage_mode_type = "GeoRedundant"

    backup_policy_vm_workload = {
      sqldaily = {
        workload_type = "SQLDataBase"
        settings = {
          compression_enabled = true
        }
        protection_policies = {
          full = {
            policy_type = "Full"
            backup = {
              frequency = "Daily"
              time      = "20:30"
            }
            retention_daily = {
              count = 30
            }
            retention_weekly = {
              count    = 8
              weekdays = ["Sunday"]
            }
          }
          log = {
            policy_type = "Log"
            backup = {
              frequency_in_minutes = 60
            }
            simple_retention = {
              count = 14
            }
          }
        }
      }
    }
  }
}

2. Accept the Built-in Default

If protection_policies is omitted, the variable default kicks in — a Full daily at 20:30 with 14-day / 4-week retention, plus a Log every 60 minutes with 7-day retention. This is intended as a sane starting point for SQL workloads:

backup_policy_vm_workload = {
  daily = {}                      # uses the default protection_policies
  explicitName = {
    name = "bpol-sql-customname-dev"
  }
}

Override the default by declaring protection_policies with the specific tiers you want — see step 1 for a full example.

3. Register Databases Against the Policy

Database-level registration (azurerm_backup_protected_vm_workload_sql_database) is not managed here. After the policy exists, register individual SQL databases via:

  • Azure Portal → Recovery Services Vault → Backup items → SQL in Azure VM
  • az backup protection enable-for-azurewl --workload-type MSSQL ...

Once a database is registered, future runs of terraform plan will not see or churn the protection — it lives outside the state managed here.

Variable Reference

backup_policy_vm_workload (nested under recovery_services_vault.<vault_key>)

Field Type Description Default
name string Override the resource name Prefix + key + suffix
workload_type string "SQLDataBase" or "SAPHanaDatabase" "SQLDataBase"
settings object Policy-wide settings (see below) {}
protection_policies map(object) One entry per backup type (see below) A sensible full + log default — see Accept the Built-in Default

settings

Field Type Description Default
time_zone string Timezone for backup schedule Root var.timezone
compression_enabled bool Enable native SQL compression on backup false

protection_policies.<key>

Each entry describes one backup tier. The policy_type determines which retention block is allowed.

Field Type Description Default
policy_type string "Full", "Differential", "Incremental", or "Log" Required
backup object Schedule (see below) Required
retention_daily object { count } — used by Full (Daily) null
retention_weekly object { count, weekdays } — used by Full null
retention_monthly object Monthly retention (see below) null
retention_yearly object Yearly retention (see below) null
simple_retention object { count } — used by Log, Differential, Incremental null

Full policies use the daily/weekly/monthly/yearly retention blocks. Log, Differential, and Incremental use simple_retention (a single flat count of days). Mixing them on the wrong policy_type will fail at apply.

backup (schedule)

Field Type Description Default
frequency string "Daily" or "Weekly" — used by Full / Differential / Incremental null
frequency_in_minutes number Minutes between backups — used by Log (typical: 15, 30, 60, 120, 240) null
time string "HH:MM" start time for daily/weekly null
weekdays list(string) Days for Weekly frequency null

Set frequency or frequency_in_minutes, never both. Log policies must use frequency_in_minutes; everything else uses frequency.

retention_monthly / retention_yearly

The workload module uses a format_type switch instead of the mutually-exclusive forms used by backup_policy_vm.

Field Type Description Default
count number Periods to retain Required
format_type string "Daily" (absolute, use monthdays) or "Weekly" (relative, use weekdays + weeks) Required
monthdays list(number) Absolute day-of-month — format_type = "Daily" only null
weekdays list(string) Weekday names — format_type = "Weekly" only null
weeks list(string) "First""Fourth", "Last"format_type = "Weekly" only null
months list(string) retention_yearly only — which months to retain Required for yearly

Naming Convention

Workload policies use the backup_policy_vm_workload prefix/suffix slot:

name_prefixes = {
  backup_policy_vm_workload = "prod-"
}

name_suffixes = {
  backup_policy_vm_workload = "-eastus2-bpol-sql"
}

Policy key sqldailyprod-sqldaily-eastus2-bpol-sql.

Set name on the policy entry to bypass prefix/suffix composition entirely.

Backup policy names allow letters, numbers, and hyphens only. Periods are rejected by the Backup API even though the error message is misleading — keep them out of both the prefix/suffix and the policy key.

Limitations

  • No protected-item resource: this repository does not yet manage azurerm_backup_protected_vm_workload_sql_database (or the SAP HANA equivalent). Database registration is a manual step.
  • No azurerm_backup_workload_container wiring either — Azure auto-discovers SQL/HANA workloads inside a registered VM once you enable the workload extension via the portal/CLI.
  • Workload policies are not interchangeable with VM policies: do not set backup_policy = "epic.sqldaily" on a windows_vms entry expecting workload protection — the backup_protected_vm module only resolves against mod_backup_policy_vm, not mod_backup_policy_vm_workload, and will fail at plan time with a key-not-found error.
  • Backup Overview — Recovery Services Vault, diagnostic settings
  • VM Backup — VM-level (crash-consistent) backup, including disk exclusion