Skip to content

Backup Restore Verification ​

Purpose ​

Periodic verification that backups are intact and restorable — before you need them. This is distinct from the actual restore procedure (Veeam Restore Procedure) and from the full DR failover test (DR Failover Procedure).

HIPAA requirement: §164.308(a)(7)(ii)(A) — data backup plan must be tested to verify restorability. Evidence goes in the DR Test Results Log.

Frequency: Quarterly, or before any planned DR test.
Owner: Rory


Verification Schedule ​

CheckFrequencyEvidence
RSV job status (all vaults)Weekly — automated via HIPAA audit emailEmail report
Veeam nightly job completionWeekly — automated via Veeam email reportEmail report
S3 Object Lock verificationQuarterlyScreenshot of bucket policy
RSV soft delete + immutabilityQuarterlyPortal screenshot
File-level test restoreQuarterly (Q2 DR test)Restore timestamp + screenshot
Full Veeam VM boot testQuarterly (Q2/Q4 DR tests)Boot screenshot, RTO timer

1 — RSV Job Status ​

What to Check ​

All Azure Recovery Services Vaults must show recent successful backup jobs. A missed backup is a gap in the RPO window.

Automated Check (Weekly) ​

The HIPAA audit email (sent weekly by ops-automation) includes a backup job summary. Review it for:

  • Any vault showing Failed or Warning status
  • Any vault with no job in the last 25 hours (missed run)

If the email hasn't arrived in over 7 days, check the ops-automation GitHub Actions for the weekly-hipaa-audit.yml workflow.

Manual Check ​

bash
# Check all backup jobs that are NOT in Completed status
az backup job list \
  --resource-group rg-prod-backup \
  --vault-name rsv-prod-backup \
  --output table \
  --query "[?properties.status!='Completed']"

Repeat for each vault:

VaultResource Group
rsv-prod-backuprg-prod-backup
rsv-identity-backuprg-identity
rsv-firewall-backuprg-firewall
rsv-dev-backuprg-dev
rsv-dde-firewall-backuprg-dde-firewall
rsv-dde-billings-backuprg-dde-billings

Any failed job needs investigation. Check the job details in the portal:
Azure Portal → Recovery Services Vault → Backup Jobs → click the failed job

Common causes:

  • VM was deallocated during the backup window
  • Snapshot limit reached (>512 recovery points) — delete old snapshots
  • Network timeout — usually self-resolves on next run

2 — Veeam Nightly Job ​

Veeam runs nightly replication from Azure Production to the AWS Backup account (863609217450), covering CGIRDPAZP01 and BIZARCAZP01.

What to Check ​

Veeam sends an email completion report after each run. The report shows:

  • Job name, status (Success / Warning / Failed)
  • Data size processed and transferred
  • Duration
  • Any VMs that failed to replicate

If no Veeam email has arrived in 25+ hours: replication failed silently or the Veeam server is down.

Investigating a Veeam Failure ​

  1. Access the Veeam management console on the Veeam server (Production subscription — access via Twingate + RDP)
  2. Home → Jobs → Backup Copy — check the last run status
  3. Click the failed job → Statistics — shows per-VM errors
  4. Common fixes:
    • AWS connectivity error: check the Veeam server's outbound connectivity to AWS S3; verify the IAM credentials used by Veeam haven't expired
    • Insufficient storage: check the S3 bucket has available capacity (it should, with lifecycle rules moving to IA/Glacier)
    • VM snapshot failure: VM may have been shut down or snapshotted by another process — retry the job

3 — S3 Object Lock Verification (Quarterly) ​

Veeam backup data in the AWS Backup account is protected by S3 Object Lock. Quarterly, verify Object Lock is still enforced — this protects backups from ransomware that gains AWS credentials.

Check Object Lock Configuration ​

bash
# Verify Object Lock is enabled on the Veeam backup bucket
aws s3api get-object-lock-configuration \
  --bucket <veeam-backup-bucket-name> \
  --profile backup \
  --output json

Expected output includes:

json
{
  "ObjectLockConfiguration": {
    "ObjectLockEnabled": "Enabled",
    "Rule": {
      "DefaultRetention": {
        "Mode": "COMPLIANCE",
        "Days": 30
      }
    }
  }
}

COMPLIANCE mode means even root cannot delete objects within the retention window. If the mode shows GOVERNANCE or is missing, escalate — this is a critical finding.

Verify a Sample Object is Locked ​

bash
# Check the lock on a specific backup object
aws s3api get-object-retention \
  --bucket <veeam-backup-bucket-name> \
  --key <path-to-backup-file> \
  --profile backup

Returns the retain-until date. If the date is in the future, the object is protected.

Take a screenshot of both outputs for compliance evidence.


4 — RSV Soft Delete and Immutability (Quarterly) ​

Azure Recovery Services Vaults should have soft delete and immutability enabled. Soft delete retains deleted backup data for 14 days; immutability prevents deletion of backup data within the retention window.

Check Soft Delete Status ​

Azure Portal → Recovery Services Vault → Properties → Security Settings

Soft delete should show Enabled. If disabled, someone turned it off — re-enable immediately and investigate who disabled it via Azure Activity Log.

bash
# Check via CLI
az backup vault backup-properties show \
  --name rsv-prod-backup \
  --resource-group rg-prod-backup \
  --query "properties.softDeleteFeatureState"

Expected: "Enabled"

Check Immutability Status ​

Azure Portal → Recovery Services Vault → Properties → Immutability

Should show Unlocked (enabled but not permanently locked — appropriate for active vaults where you may need to adjust policy). Never lock permanently on active production vaults — locking is irreversible and prevents policy changes.


5 — File-Level Test Restore (Quarterly) ​

A quarterly file restore proves the backup is actually usable — not just that the job ran successfully.

Procedure ​

  1. Pick a non-critical VM from the Production RSV — a server that is not customer-facing and can tolerate a brief additional load
  2. Azure Portal → rsv-prod-backup → Backup Items → Azure Virtual Machine → [target VM]
  3. Click File Recovery (not Restore VM)
  4. Select the most recent recovery point
  5. Click Download Script — note the date/time of the recovery point and the password
  6. Run the script on any Windows machine with Twingate access to the vault
  7. Confirm the backup disk mounts successfully as a drive letter
  8. Navigate to a known file (e.g., C:\Windows\System32\drivers\etc\hosts — always present)
  9. Verify the file is readable
  10. Click Unmount Disks in the portal
  11. Record: test date, VM used, recovery point date, result (Success / Failure)

Evidence to Capture ​

  • Screenshot of the mounted drive in Windows Explorer
  • Screenshot of the recovery point selected
  • Timestamp of when the mount succeeded

Add findings to the DR Test Results Log.


6 — Veeam VM Boot Test (Q2 / Q4 DR Tests) ​

A full Veeam VM boot test is part of the Q2 and Q4 DR tests — not done independently. For the full procedure see DR Failover Procedure.

Verification target: at least 3 tier-1 workloads must boot cleanly from Veeam replica with no manual intervention.

The tier-1 workloads are:

  • CGIRDPAZP01 — DR domain controller
  • BIZARCAZP01 — business application server
  • Any third workload specified in the Q2/Q4 test plan

7 — PostgreSQL Database (SecOps Platform) ​

The SecOps platform database (psql-secops-prod) uses Azure Database for PostgreSQL with automated PITR (point-in-time restore) enabled.

Verify PITR is Enabled ​

Azure Portal → psql-secops-prod → Overview

Check "Backup retention period" — should be 7 days minimum. The earliest restore point shown must be within the configured retention.

bash
az postgres flexible-server show \
  --name psql-secops-prod \
  --resource-group rg-logging-logs \
  --query "{backupRetentionDays:backup.backupRetentionDays, geoRedundantBackup:backup.geoRedundantBackup}"

Test PITR Restore (Annual, During DR Test) ​

During the annual DR test, verify PITR works by restoring to a test server:

bash
az postgres flexible-server restore \
  --resource-group rg-logging-logs \
  --name psql-secops-pitr-test \
  --source-server psql-secops-prod \
  --restore-time "2026-05-24T01:00:00Z"

Connect to the restored server, verify the data looks correct for the target timestamp, then delete the test server:

bash
az postgres flexible-server delete \
  --resource-group rg-logging-logs \
  --name psql-secops-pitr-test \
  --yes

What to Do If Verification Fails ​

FindingAction
RSV backup job failedInvestigate and resolve; check next day's run; document if gap occurred
Veeam didn't run in 25hAccess Veeam console, check job status, fix connectivity or credentials
S3 Object Lock missing or GOVERNANCE modeCRITICAL — escalate to Rory immediately; do not delete any objects
RSV soft delete disabledRe-enable; check Activity Log for who disabled it; treat as security event
File restore fails (corrupt or inaccessible)Open issue; test a different recovery point; if all points fail, escalate
PITR restore failsCheck Azure Status for PostgreSQL service issues; open support ticket if needed

All failures are logged in the DR Test Results Log as open gaps with severity, owner, and remediation status.


HIPAA Evidence Package ​

For §164.308(a)(7)(ii)(A) — backup plan testing:

  1. This document — the verification procedure
  2. Weekly HIPAA audit emails — RSV job status automated checks
  3. Veeam email reports — nightly replication confirmation
  4. Quarterly verification screenshots — S3 Object Lock, RSV immutability, file restore
  5. DR Test Results Log — formal test outcomes including RTO/RPO achieved
  6. DR Test Plan documents (Q2/Q4) — shows structured scope


Document History ​

DateChangeAuthor
May 2026Initial draft — weekly/quarterly verification checks for RSV, Veeam, S3 Object Lock, RSV immutability, file restore, PostgreSQL PITR. HIPAA evidence mapping.Rory

Internal use only — Cirius Group