Backup and Disaster Recovery Questions
Keeping data durable and recoverable when systems fail: backup design (full, incremental, differential, and snapshot strategies; point-in-time recovery), backup verification and restore testing, retention and archival policy (including compliance retention and legal holds), encryption and key management for backups, and disaster-recovery planning measured against recovery-time and recovery-point objectives (RTO/RPO). Tests whether a candidate can design a backup strategy that actually restores, choose the right retention tier for a business's downtime and data-loss tolerance, and operate backup systems safely under failure, compliance, and ransomware threats. Distinct from code-level fault-tolerance patterns (circuit breakers, retries, bulkheads) and multi-region failover architecture, which belong to high-availability-and-disaster-recovery.
Design an automated restore verification harness that periodically restores backups into isolated test environments and runs application-level acceptance tests across multiple stacks (web app, database, message queue). Describe orchestration, environment provisioning (IaC), test selection, data obfuscation for PII, pass/fail criteria, and reporting/alerting integration.
Sample Answer
Direct answer
The harness is a pipeline, not a script: an orchestrator triggers on a schedule or after each backup completes, provisions a fully isolated environment via Infrastructure as Code (IaC), restores the target backup into it, masks any PII before anything or anyone else can touch the data, runs a tiered set of tests from cheap-and-fast to expensive-and-thorough, evaluates explicit pass/fail criteria, and reports results with alerting wired to page on failure, then tears the environment down regardless of outcome so cost stays bounded.
Orchestration
A scheduler or pipeline service drives the whole run as an explicit state machine (provision, restore, mask, test, report, teardown), triggered either on a cadence (nightly for critical systems, weekly for the rest) or immediately after each new backup job completes, so a bad backup is caught close to when it was created rather than discovered weeks later during an actual incident. Each stage has its own timeout and retry policy so a single stuck restore does not block the entire pipeline indefinitely.
Environment provisioning (IaC)
Every run gets a fully isolated environment: a dedicated network segment or namespace with no route to production, provisioned via Terraform, Ansible, or Kubernetes manifests, sized close enough to production for the test to be meaningful. Teardown is automatic and unconditional (pass or fail), and teardown itself should be verified with a periodic orphaned-resource sweep, since a harness that silently leaks infrastructure on failed runs quietly becomes an expensive habit nobody notices until the cloud bill does.
Test selection, tiered by cost
- Cheapest, every run: did the restore complete, did the system boot or start successfully.
- Fast, every run: data integrity checks (checksums, row counts, referential integrity).
- Moderate, every run: application-level smoke tests, can the app start, connect to its restored database, and serve a handful of key endpoints.
- Expensive, rotating subset: the same full acceptance test suite used in CI, run against the restored stack, on a schedule lighter than nightly (for example weekly) or specifically before a run is counted as an official quarterly drill, since running the full suite on every single nightly restore is usually not affordable at scale.
Data obfuscation for PII
A restored environment is, by construction, a full copy of production data landing in a less-trusted test context, so masking has to happen automatically, as a gate, before any test or human gets access to the restored data, not as an optional cleanup step afterward. Use deterministic tokenization, the simpler default choice, or format-preserving encryption, worth the extra complexity only when the masked value must still pass a format validator downstream, for fields that need to stay joinable across tables (a customer_id that multiple tables reference), and irreversible masking for free-text or clearly sensitive fields (SSNs, free-text notes). No query against the restored environment, automated or human, should be possible until masking has run and been verified complete.
Pass/fail criteria
Restore completed within the target time (measured end to end from trigger to verified functional, on the same basis as the system's RTO, not from "data copy complete," which understates the real recovery time by omitting validation). Zero integrity-check failures. All application smoke tests passing. On the rotating full-suite tier, an acceptance-test pass rate above a defined threshold. Any failure marks that specific backup generation as suspect and pages the on-call rather than silently retrying until it happens to pass, which would hide a real, recurring problem.
Reporting and alerting integration
Every run writes a structured result (pass/fail per stage, timing, logs) to a results store so trends are visible over time, for example restore time creeping upward month over month well before it breaches SLA. Failures alert immediately, paging for Tier-0 systems and filing a ticket for lower tiers, with enough context (which stage failed, relevant logs) attached that triage does not require re-running the whole pipeline first. A periodic rollup (monthly, say) reports restore-success rate to leadership as a real reliability metric, distinct from and more meaningful than "backups completed," which only proves bytes were written, not that they are usable.
Explain the differences between full, incremental, and differential backups. For each type, describe how the restore operation actually works, typical storage and I/O characteristics, how complex the recovery chain gets, and a realistic scenario where you'd prefer that type over the others.
Sample Answer
Direct answer
The single decision that determines everything else about a backup type is what it actually captures: a full backup captures every byte, an incremental backup captures only what changed since the last backup of any kind, and a differential backup captures everything that changed since the last full backup (ignoring any differentials in between). That one difference cascades into how restore works, how much storage and I/O each consumes, how long and fragile the recovery chain gets, and which scenario each fits. Point-in-time recovery via transaction-log shipping is a related but separate mechanism and isn't one of the three types asked about here.
Structured elaboration
Full backups.
- What it captures: a complete copy of all data at the moment the backup runs.
- Restore mechanics: apply a single file. No assembly, no ordering to get right.
- Storage and I/O: highest of the three, every run duplicates the entire dataset; backup-time I/O is also the highest since the whole dataset is read and written every time.
- Recovery chain complexity: none, it's a chain of length one.
- Realistic scenario: as the periodic anchor point underneath a mixed strategy (a weekly full backing incremental or differential backups on the days in between), or as a one-off just before a risky operation like a schema migration, where you want the simplest possible restore path available if it goes wrong, not a clever one.
Incremental backups.
- What it captures: only the data changed since the immediately preceding backup, whatever type that was (the last full, or the last incremental).
- Restore mechanics: restore the last full, then apply every incremental since it, strictly in order. If backups were taken Mon (full), Tue, Wed, Thu, Fri, Sat, Sun (incrementals), restoring to Sunday means applying all six incrementals on top of the full in sequence.
- Storage and I/O: lowest per individual backup run, since only changed data is captured each time, so this is the cheapest option in steady-state storage and the fastest to actually take.
- Recovery chain complexity: the highest of the three, and it grows every day since the last full. A single corrupted or missing incremental in the middle of that chain breaks the restore for every day after it, not just that one day.
- Realistic scenario: very large datasets with a tight backup window and a real storage-cost driver, e.g. a multi-terabyte warehouse where a nightly full backup wouldn't finish before the maintenance window closes and daily full copies would be prohibitively expensive to store, and where actual restores are rare enough that a longer, multi-file restore assembly is an acceptable trade for the ongoing savings.
Differential backups.
- What it captures: everything changed since the last full backup (not since the last differential), so each day's differential is a superset of the previous day's.
- Restore mechanics: restore the last full, then apply only the single most recent differential. Restoring to Sunday in the same Mon-Sun example above means applying the full plus only Sunday's differential, the Tue through Sat differentals are never needed.
- Storage and I/O: between full and incremental, and it grows every day since the last full as more cumulative change gets folded into each new differential; by the day before the next full, the differential can approach the size of a full backup of just the changed rows.
- Recovery chain complexity: fixed at two, full plus latest differential, regardless of how many days have passed since the last full. Losing an older differential doesn't matter because only the newest one is ever used.
- Realistic scenario: systems where restore speed and restore reliability matter more than minimizing backup-time storage, e.g. a transactional system with a demanding recovery-time target where you don't want six independent incremental files all needing to be intact to get back online; you're trading a bit more storage for a restore path that can't be broken by losing an old file.
Worked example, basis of every number stated. Assume a 500 GB database with a constant 10 GB/day of changed data (this is the daily delta measured in changed bytes, treated as constant for illustration; a real system's WAL (write-ahead log, the database's own transaction log) volume can exceed the net-changed-bytes figure because of engine-level effects like full-page writes (the database re-logging an entire disk page rather than just the changed bytes, the first time that page changes after a checkpoint), so treat 10 GB/day as the backup-relevant change volume, not raw log volume). A full backup runs Monday: 500 GB. Over the following six days:
- Incremental: each day backs up only that day's 10 GB, so Tue through Sun each write a 10 GB file, roughly 60 GB total across the week. Restoring to Sunday means applying the 500 GB full plus six 10 GB incrementals in order: seven files, seven steps.
- Differential: each day backs up everything since Monday's full, so the differentials are 10 GB (Tue), 20 GB (Wed), 30 GB (Thu), 40 GB (Fri), 50 GB (Sat), and 60 GB (Sun), since each day rolls in one more day's worth of change on top of the same base. Restoring to Sunday means applying the 500 GB full plus only the 60 GB Sunday differential: two files, two steps, even though the Sunday differential file itself is as large as the entire incremental week combined.
That last line is the trade-off in one sentence: incremental keeps each individual backup small at the cost of a restore chain that gets longer and more fragile every day; differential keeps the restore chain fixed at two files at the cost of each individual backup getting larger every day since the last full.
Technical-coding: Write a Bash script that runs in /var/backups and rotates backup files named YYYY-MM-DD.tar.gz. Keep the last 7 daily backups, 4 weekly backups (one per week), and 6 monthly backups (one per month). The script should be idempotent and safe to run from cron. You do not need to implement backup creation, only rotation/pruning logic.
Sample Answer
Direct answer
The script below implements a grandfather-father-son (GFS) rotation over dated YYYY-MM-DD.tar.gz files: it keeps the 7 most recent daily backups outright, then keeps one representative (the most recent) backup from each of the last 4 distinct ISO calendar weeks, then one representative from each of the last 6 distinct calendar months, and deletes anything not required by any of those three rules. Because the keep-set is recomputed purely from whatever dated files currently exist, running it repeatedly with no new backups added is a true no-op, which is what idempotent means here, and it never touches files it does not recognize as YYYY-MM-DD.tar.gz.
The script
#!/usr/bin/env bash
# rotate-backups.sh
# Prunes dated backup archives (YYYY-MM-DD.tar.gz) under a GFS-style
# retention policy: last 7 daily, last 4 weekly, last 6 monthly.
# Idempotent, cron-safe. Does not create backups, only rotates/prunes them.
set -euo pipefail
BACKUP_DIR="${1:-/var/backups}"
LOCK_DIR="$BACKUP_DIR/.rotate-backups.lock.d"
KEEP_DAILY=7
KEEP_WEEKLY=4
KEEP_MONTHLY=6
log() { printf '%s [rotate-backups] %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$1"; }
[ -d "$BACKUP_DIR" ] || { log "error: $BACKUP_DIR does not exist"; exit 1; }
# Cron-safety: refuse to run concurrently with another instance.
if command -v flock >/dev/null 2>&1; then
exec 9>"$BACKUP_DIR/.rotate-backups.lock"
flock -n 9 || { log "another rotation is already running, exiting"; exit 0; }
else
# Portable fallback where flock(1) is unavailable (mkdir is atomic).
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
log "another rotation is already running, exiting"
exit 0
fi
fi
iso_week_key() {
# $1 = YYYY-MM-DD -> "YYYY-WW" (ISO year-week)
if date -d "$1" +%s >/dev/null 2>&1; then
date -d "$1" +%G-%V
else
date -j -f "%Y-%m-%d" "$1" +%G-%V
fi
}
is_valid_date() {
# $1 = candidate date string; true only if it is a real calendar date
# (the filename regex below accepts digit-shape strings like 2026-13-40
# that are not real dates, so this second check is load-bearing).
if date -d "$1" >/dev/null 2>&1; then
return 0
elif date -j -f "%Y-%m-%d" "$1" >/dev/null 2>&1; then
return 0
else
return 1
fi
}
dates=()
while IFS= read -r -d '' path; do
base="$(basename "$path")"
d="${base%.tar.gz}"
if [[ "$d" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] && is_valid_date "$d"; then
dates+=("$d")
else
log "skipping non-conforming file: $base"
fi
done < <(find "$BACKUP_DIR" -maxdepth 1 -type f -name '*.tar.gz' -print0)
if [ "${#dates[@]}" -eq 0 ]; then
log "no dated backups found in $BACKUP_DIR, nothing to rotate"
rmdir "$LOCK_DIR" 2>/dev/null || true
exit 0
fi
sorted=()
while IFS= read -r line; do
sorted+=("$line")
done < <(printf '%s\n' "${dates[@]}" | sort -u -r)
DAILY_FILE=$(mktemp "${TMPDIR:-/tmp}/rotate-daily.XXXXXX")
WEEKLY_FILE=$(mktemp "${TMPDIR:-/tmp}/rotate-weekly.XXXXXX")
MONTHLY_FILE=$(mktemp "${TMPDIR:-/tmp}/rotate-monthly.XXXXXX")
trap 'rm -f "$DAILY_FILE" "$WEEKLY_FILE" "$MONTHLY_FILE"; rmdir "$LOCK_DIR" 2>/dev/null || true' EXIT
n=0
for d in "${sorted[@]}"; do
[ "$n" -ge "$KEEP_DAILY" ] && break
printf '%s\n' "$d" >> "$DAILY_FILE"
n=$((n + 1))
done
n=0
seen_weeks=""
for d in "${sorted[@]}"; do
[ "$n" -ge "$KEEP_WEEKLY" ] && break
wk="$(iso_week_key "$d")"
case " $seen_weeks " in
*" $wk "*) continue ;;
esac
seen_weeks="$seen_weeks $wk"
printf '%s\n' "$d" >> "$WEEKLY_FILE"
n=$((n + 1))
done
n=0
seen_months=""
for d in "${sorted[@]}"; do
[ "$n" -ge "$KEEP_MONTHLY" ] && break
mo="${d:0:7}"
case " $seen_months " in
*" $mo "*) continue ;;
esac
seen_months="$seen_months $mo"
printf '%s\n' "$d" >> "$MONTHLY_FILE"
n=$((n + 1))
done
kept=0
pruned=0
for d in "${sorted[@]}"; do
reason=""
grep -qxF "$d" "$DAILY_FILE" 2>/dev/null && reason="${reason}daily,"
grep -qxF "$d" "$WEEKLY_FILE" 2>/dev/null && reason="${reason}weekly,"
grep -qxF "$d" "$MONTHLY_FILE" 2>/dev/null && reason="${reason}monthly,"
f="$BACKUP_DIR/$d.tar.gz"
if [ -n "$reason" ]; then
log "KEEP $d.tar.gz (${reason%,})"
kept=$((kept + 1))
else
rm -f -- "$f"
log "PRUNE $d.tar.gz"
pruned=$((pruned + 1))
fi
done
log "rotation complete: kept=$kept pruned=$pruned total=${#sorted[@]}"
Worked example: run cold, real output, including a real bug caught by running it
Extracted unmodified and run cold on a real machine (bash 3.2, the actual default /bin/bash shipped on this box, no GNU date, no flock binary, so every portability fallback in the script is genuinely exercised, not just theoretically present). 73 dated files were generated, one per day from 2026-06-01 through 2026-08-12, plus a README.txt (wrong extension) and later a weekly-full-2026.tar.gz (right extension, non-date name) and a 2026-13-40.tar.gz (right shape, not a real calendar date).
First run against the 73 real dated files, actual output (trimmed to the summary; every individual KEEP/PRUNE line was also inspected):
$ bash ./rotate-backups.sh backups
...
KEEP 2026-08-12.tar.gz (daily,weekly,monthly)
KEEP 2026-08-11.tar.gz (daily)
KEEP 2026-08-10.tar.gz (daily)
KEEP 2026-08-09.tar.gz (daily,weekly)
KEEP 2026-08-08.tar.gz (daily)
KEEP 2026-08-07.tar.gz (daily)
KEEP 2026-08-06.tar.gz (daily)
PRUNE 2026-08-05.tar.gz
...(62 PRUNE lines total)...
KEEP 2026-08-02.tar.gz (weekly)
KEEP 2026-07-31.tar.gz (monthly)
KEEP 2026-07-26.tar.gz (weekly)
KEEP 2026-06-30.tar.gz (monthly)
rotation complete: kept=11 pruned=62 total=73
exit code: 0
11 kept matches the math: 7 daily (Aug 6-12), plus 4 distinct weekly reps (Aug 12, Aug 9, Aug 2, Jul 26, two of which overlap the daily set), plus 3 distinct monthly reps found in the data (Aug 12, Jul 31, Jun 30, since the test data only spans 3 calendar months so monthly correctly returned fewer than the configured cap of 6), unioned down to 11 unique files. Running it again immediately afterward confirms idempotency:
$ bash ./rotate-backups.sh backups
...(same 11 KEEP lines, zero PRUNE lines)...
rotation complete: kept=11 pruned=0 total=11
exit code: 0
A real bug was caught by this exact cold-run process and is worth reporting explicitly. Before the current script, an earlier version's iso_week_key was called directly in a command substitution (wk="$(iso_week_key "$d")") with only a filename-shape regex (^[0-9]{4}-[0-9]{2}-[0-9]{2}$) guarding entry into the dates array, no real calendar-date validation. Dropping a file named 2026-13-40.tar.gz into the directory (digit-shape valid, month 13 and day 40 are not) and running that earlier version crashed the whole script under set -e, because the BSD date -j -f call inside the substitution failed and, unlike a command guarded by if, a failing command substitution assignment does trip errexit (the formal name for the set -e behavior enabled at the top of the script via set -euo pipefail):
$ bash ./rotate-backups-BROKEN.sh backups
Failed conversion of `2026-13-40' using format `%Y-%m-%d'
date: illegal time format
exit code: 1
The shipped script fixes this with a dedicated is_valid_date check (guarded by if, which is exempt from errexit) applied at file-collection time, so a bad filename is now cleanly skipped and logged instead of aborting the run:
$ bash ./rotate-backups.sh backups
skipping non-conforming file: weekly-full-2026.tar.gz
skipping non-conforming file: 2026-13-40.tar.gz
KEEP 2026-08-12.tar.gz (daily,weekly,monthly)
...
rotation complete: kept=11 pruned=0 total=11
exit code: 0
Empty-directory and missing-directory behavior were also confirmed directly: an empty backup directory logs "no dated backups found... nothing to rotate" and exits 0; a nonexistent directory logs an error and exits 1; neither leaves a stray lock directory behind.
Trade-offs and design notes
- Idempotency here is a property of the algorithm, not a flag. The keep-set for daily/weekly/monthly is recomputed fresh from whichever dated files are currently present; since files the algorithm decides to prune were never in the keep-set to begin with, removing them cannot change what the keep-set would have been, so a second run against the survivors alone reproduces the exact same keep-set with zero further deletions.
- Cron-safety uses
flockwhen available and falls back to an atomicmkdir-based lock when it is not (there is noflockbinary on stock macOS, which is exactly the environment this was tested cold against), so a second invocation overlapping with a still-running one exits cleanly rather than racing on the same files. - The GNU-versus-BSD
datehandling is what made the cold run meaningful rather than theoretical: this genuinely runs on bothdate -d(GNU/Linux) anddate -j -f(BSD/macOS) systems because the detection is anif-guarded probe, not an assumption about which platform the reader is on.
As a senior systems administrator you must recommend whether to purchase a commercial backup platform or build an internal backup solution for a global enterprise. Create a decision framework covering total cost of ownership, SLAs, feature gaps, vendor lock-in, security and compliance, operational overhead, and a final recommendation process including pilots and evaluation criteria.
Sample Answer
Direct answer
Default to buy unless there is a specific, named reason not to: backup infrastructure is rarely a competitive differentiator, getting it wrong is close to existential risk, and a commercial vendor amortizes that risk (and the engineering behind avoiding it) across every one of its customers, not just this one enterprise. Build only when a genuine, well-documented gap exists (an unsupported source type, a compliance requirement no vendor meets, or a cost structure that is provably worse at the organization's actual scale) and the organization is willing to own that gap forever, not just through the first successful pilot.
Total cost of ownership (TCO), on the same basis
Compare like for like: total cost over a fixed multi-year horizon (3-5 years is typical for infrastructure decisions), not year-1 build cost against annual license cost, because build's year-1 cost is artificially low (not much has been built yet) while license cost is already run-rate from day one. Illustrative worked example, explicitly an ESTIMATE and not a market quote: protecting 2 PB of data.
- Buy: licensing around $0.02 per GB per month (ESTIMATE) times 2,000,000 GB gives about $40,000 per month, or $480,000 per year, plus roughly one FTE to operate at $150,000 fully loaded, for about $630,000 per year.
- Build: three senior engineers at $180,000 fully loaded each is $540,000 per year, plus infrastructure cost for the backup engine itself (ESTIMATE, around $100,000 per year), for about $640,000 per year in direct run cost, similar order of magnitude to buy.
The point of this exercise is not that the two numbers come out close (they will not always), it is that build's TCO also carries a shadow cost the run-rate comparison misses: the multi-year period before build reaches feature parity with a mature commercial product, during which the organization either operates with real feature gaps or pays for both paths at once. Any real comparison must include that ramp period, not just steady-state run cost.
SLA
A commercial vendor typically offers a contractual SLA (for example 99.9% platform availability, defined support response times) with financial penalties or credits if missed, giving external accountability. Build means the organization's own SRE team is the SLA, with no outside party to escalate to and no consequence beyond the internal cost of the outage itself.
Feature gaps
Commercial platforms usually arrive with a broad, mature feature set (deduplication, immutability/object-lock, connectors for many source systems) on day one. Build lets the organization match its exact requirements precisely but takes real time to reach parity, and some long-tail features may never be built without dedicated, ongoing investment, since they compete for the same engineering time as everything else the team owns.
Vendor lock-in
Commercial risk: proprietary backup formats can make it hard to leave without a costly migration, and pricing or support quality can change unilaterally once switching cost is high. Build risk is the mirror image: full control, but the organization now owns that control forever, including the bus-factor risk of the few engineers who understand the internals leaving.
Security and compliance
Commercial vendors commonly carry third-party attestations (SOC 2 and ISO 27001, general-purpose security-practice attestations most enterprise vendors carry, plus industry-specific ones like HIPAA for healthcare data or FedRAMP for US federal government use, where relevant) that materially reduce the organization's own audit burden, since "our vendor is independently certified" is a much shorter conversation with an auditor than "we self-attest to our own home-built system." Build means the organization must self-certify everything and carries full responsibility for the security posture of a system it wrote, with no vendor security team to lean on.
Operational overhead
Commercial (especially SaaS) delegates most patching and upgrade burden to the vendor. Build means the organization's own on-call absorbs every edge case (encryption bugs, restore corruption, scaling limits) with no vendor support line to escalate to when something genuinely strange happens at 3 a.m.
Final recommendation process: pilots and evaluation criteria
- Shortlist two to three commercial vendors plus, only if a real gap was identified above, a scoped build proof-of-concept limited to a single workload class.
- Define evaluation criteria upfront, before the pilot starts, so the process is not retrofitted to favor whichever option looked better first: RTO/RPO actually achieved in a real restore test, cost per TB at the organization's actual scale (not list price), restore success rate across several drill runs, integration effort measured in engineer-weeks, and pass/fail on the security review.
- Weight criteria by organizational priority (a compliance-heavy organization weights security/compliance higher than a small startup would).
- Time-box the pilot (roughly 6-8 weeks is typical) with a defined go/no-go gate, so the evaluation itself does not become the indefinite, unbounded project that build risk warns against.
After detecting a ransomware outbreak that encrypted production VMs and some backups, describe a prioritized restore plan for an enterprise with 2,000 VMs. Include immediate containment, prioritization criteria (e.g., AD, DNS), recovery steps, validation, and stakeholder communication.
Sample Answer
Direct answer
At 2,000 VMs, sequential restore is not a plan, it is a multi-week outage, so the answer has to be a tiering scheme executed in parallel within each tier, gated by containment and by trust in the backup itself (the scenario states some backups were also encrypted, which means the backup infrastructure was reachable by the attacker and every "clean" backup must be verified before it is trusted, not assumed clean because it predates the encryption event).
Immediate containment
- Isolate affected network segments to stop lateral spread: disable inter-host SMB/RDP where feasible, segment VLANs, and pull the affected segment's route to the rest of the network rather than shutting everything down blindly.
- Rotate all privileged credentials immediately, especially anything with domain admin or backup-admin rights, since ransomware operators that reach 2,000 VMs typically did so via a compromised privileged account, not purely via a worm.
- Power off (do not destroy) actively encrypting hosts to stop further damage while preserving forensic evidence on disk; a live host still encrypting is actively destroying data every additional minute it stays up.
- Because "some backups" were encrypted, immediately isolate and lock down the backup infrastructure itself (separate credentials, separate network path) and treat every backup repository as suspect until integrity-checked, not just the ones known to be hit.
- Preserve evidence: snapshot volatile state and logs from a representative sample of affected hosts before any restore activity overwrites it, since the same incident will need a root-cause and likely a breach investigation.
Prioritization criteria (why AD and DNS come first)
Everything else depends on identity and name resolution, so restoring an application server before its supporting Active Directory (AD) domain controllers and DNS are trustworthy just means restoring a system that cannot authenticate or be found. Tiering:
- Tier 0, trust root: AD domain controllers, DNS, DHCP, time sync (NTP), and the backup, EDR (endpoint detection and response, the agent that watches hosts for malicious behavior), and SIEM (security information and event management, the centralized log and alert aggregator) infrastructure itself. These are restored from a verified-clean backup taken before the earliest known indicator of compromise, not simply "yesterday's" backup, because ransomware frequently dwells silently for days to weeks before triggering encryption, and restoring from a backup taken during that dwell time reintroduces the same backdoor.
- Tier 1, core infrastructure: hypervisor management plane, network devices/firewalls, security tooling.
- Tier 2, business-critical applications: ranked by a pre-existing business impact analysis (revenue-generating systems, safety-critical systems, systems under regulatory SLA), not restored ad hoc by whoever asks loudest.
- Tier 3, everything else: restored by department priority and dependency order once the tiers above are stable.
Recovery steps, per VM
For each VM: identify a backup generation confirmed to predate the earliest compromise indicator; restore it into an isolated recovery network with no route to production; run anti-malware/EDR scanning and file-integrity checks against it; identify and close the specific vulnerability believed to have allowed the initial compromise (unpatched service, exposed credential, phishing-delivered payload) before reconnecting; rotate any credentials that lived on that VM; only then move it onto the production network.
Validation
Before declaring a restored VM production-ready: automated boot and health check; malware/EDR scan clean; checksum or hash comparison of critical files against known-good; application-level smoke tests for anything customer-facing; and an observation window (hours, not minutes) watching for re-encryption or beaconing behavior before the VM is trusted unattended, since a restored-but-still-backdoored host will often stay quiet until it reconnects to its command-and-control infrastructure.
Stakeholder communication
A single incident commander owns messaging so technical recovery and business communication do not conflict. A pre-agreed cadence (for example every 30-60 minutes during the active phase) goes to executives, legal, and PR. Because most modern ransomware is double-extortion (data exfiltrated, not only encrypted), legal must assess breach-notification obligations early rather than waiting for full recovery, and customer-facing status updates should be honest about scope without disclosing details that would help the attacker or violate the ongoing investigation. Recovery progress should be reported by tier ("Tier 0 identity restored and verified, Tier 1 in progress") since that is a metric stakeholders can track and it maps to what is actually unblocking further recovery.
Unlock Full Question Bank
Get access to all Backup and Disaster Recovery interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.