Skip to main content
INS // Insights

AWS Backup Restore Testing That Proves RTO

Updated September 2026 · 5 min read

AWS Backup restore testing is the control we implement when an examiner asks for evidence that recovery works, not evidence that a vault exists. A backup plan, a vault ARN, and a green AWS Backup console tile satisfy almost nobody on a Type II sample. They want a restore job with timestamps, a validation result, and a duration they can compare to the RTO in your policy. That is what restore-test plans are for.

We do not claim this is an examination opinion. We claim it produces the artifact CC7 / availability narratives actually get sampled: periodic restore, measured duration, signed validation, automatic cleanup.

A Vault Is Not an RTO

Availability criteria and the AWS Well-Architected reliability practice both say the same thing: recover from backup on a schedule and check the clock. REL09-BP04 is the public version. The anti-pattern we walk into:

  • Daily backups, never restored.
  • A tabletop “we would click Restore.”
  • One heroic restore after an incident, with no job ID in the evidence folder.
  • Restores into the production account that nobody wants to repeat.

AWS Backup’s restore testing feature is the managed version of that drill: a cron, a start window, a recovery-point selection, inferred restore metadata, job duration monitoring, and optional validation. Documentation lives at Restore testing.

AWS Backup Restore Testing Plans We Ship

A restore testing plan is two API calls: CreateRestoreTestingPlan then CreateRestoreTestingSelection. We keep them in Terraform so the plan cannot drift off the evidence calendar.

{
  "RestoreTestingPlanName": "prod-rto-weekly",
  "ScheduleExpression": "cron(30 6 ? * SUN *)",
  "ScheduleExpressionTimezone": "America/Anchorage",
  "StartWindowHours": 2,
  "RecoveryPointSelection": {
    "Algorithm": "LATEST_WITHIN_WINDOW",
    "SelectionWindowDays": 7,
    "IncludeVaults": ["arn:aws:backup:us-west-2:123456789012:backup-vault:prod"],
    "RecoveryPointTypes": ["SNAPSHOT"]
  }
}

SelectionWindowDays is measured from job start, not from the cron. If backups are daily and the start window is two hours, a window of 7 days is safe. A window shorter than backup frequency plus start window is how you get empty selections and a “test” that never ran.

Selection is scoped. We do not restore every RDS instance every Sunday. We restore:

  • One production-class RDS (or Aurora) into an isolated restore account.
  • One EBS volume that backs a stateful service.
  • One S3 backup (if S3 is in the backup plan) to a scratch prefix.

Random recovery points (RANDOM_WITHIN_WINDOW) are what we add in the second quarter, once weekly latest-point tests are boring. Examiners like “not always the newest snapshot.” Finance likes that we do not restore the entire vault.

aws backup create-restore-testing-selection \
  --restore-testing-plan-name prod-rto-weekly \
  --restore-testing-selection '{
    "RestoreTestingSelectionName": "prod-rds",
    "IamRoleArn": "arn:aws:iam::123456789012:role/backup-restore-tester",
    "ProtectedResourceType": "RDS",
    "ProtectedResourceArns": ["arn:aws:rds:us-west-2:123456789012:db:prod"],
    "ValidationWindowHours": 2
  }'

The IAM role is least-privilege restore in the destination account, not the production admin role. Restore testing creates new resources; we tag them restore-test=true and let AWS Backup delete them after the validation window. Leaving restored RDS instances running is how a restore-test program becomes a new cost center.

Validation Is the Evidence, Not the Restore Job Status

COMPLETED means AWS Backup finished constructing the resource. It does not mean the database accepted connections, the volume had a filesystem, or the row counts matched. We attach an EventBridge rule on restore job COMPLETED and a Lambda that:

  1. Waits for the engine to accept a connection (RDS) or a filesystem check (EBS).
  2. Runs a small integrity query or checksum the application team owns.
  3. Calls PutRestoreValidationResult with SUCCESSFUL or FAILED.
  4. Records restore_start, restore_completed, validation_completed, and elapsed vs RTO in an evidence bucket.
# Ponytail: single-account validation; multi-account EventBridge is the upgrade
import boto3, os, time

backup = boto3.client("backup")
rds = boto3.client("rds")

def handler(event, _context):
    job_id = event["detail"]["restoreJobId"]
    job = backup.describe_restore_job(RestoreJobId=job_id)
    created = job["CreationDate"]
    completed = job.get("CompletionDate")
    # application-owned check — connection + SELECT 1
    ok = wait_for_rds(job["CreatedResourceArn"])
    elapsed = (completed - created).total_seconds()
    rto = int(os.environ["RTO_SECONDS"])
    status = "SUCCESSFUL" if ok and elapsed <= rto else "FAILED"
    backup.put_restore_validation_result(
        RestoreJobId=job_id,
        ValidationStatus=status,
        ValidationStatusMessage=f"elapsed={elapsed}s rto={rto}s ok={ok}",
    )

Once a validation status is set, it cannot be changed. That is what we want for a Type II window. The examiner pulls DescribeRestoreJob / the Backup console validation column / our evidence object. We also emit the duration to CloudWatch so a miss against RTO pages the on-call, not the auditor.

What We Hand Over for the Sample

The packet is boring on purpose:

  1. Restore testing plan + selection (Terraform state or GetRestoreTestingPlan).
  2. Last N job IDs with start, end, duration, validation status.
  3. RTO from the policy (hours) vs measured duration (minutes).
  4. Cleanup proof (resources gone after ValidationWindowHours).
  5. Exceptions: any job that failed, with the ticket that fixed the backup — not a silent skip.

This sits next to SOC 2-ready AWS architecture and GuardDuty / Security Hub aggregation. Backup without restore testing is a detective story with no plot. Restore testing without a destination account is how you contaminate production.

We deliver the plan, the validation Lambda, the evidence prefix, and the runbook. That is AWS cloud infrastructure work with a compliance artifact, not a GRC-tool checkbox.

Need restore-test plans that prove RTO? 907-841-8407 or contact@rutagon.com.

Talk to us about AWS Backup restore testing →

Frequently Asked Questions

Does a successful backup job prove we can restore within RTO?

No. Backup success proves a recovery point was written. RTO is a restore-and-validate duration. Only a restore job with timestamps — and a validation that the resource is usable — speaks to RTO. That is why we schedule restore-test plans instead of exporting vault screenshots.

Can restore testing run in the production account?

It can. We do not. Restored identifiers, security groups, and leftover instances create risk and cost. A dedicated restore account (or OU) with a one-way copy from the production vault is the pattern we ship. The examiner still sees a real restore; production does not absorb the side effects.

What if the restore finishes after our stated RTO?

Mark validation FAILED, page, and treat it as a control exception for the window. Either the RTO in the policy is fiction, the instance class used for restore is too small, or the backup is the wrong type (snapshot vs continuous). Changing the policy after a miss, without a ticket, is worse than the miss.

Do we need to restore every resource type every week?

No. Sample the systems that carry the RTO in the availability policy — usually the primary datastore and one stateful disk. Rotate the specific resource IDs across the observation window so the sample is not always the same friendly database. Full-fleet weekly restores are how the test becomes too expensive to keep.

Does AWS Backup restore testing replace a SOC 2 examination?

No. It is an automated drill that produces evidence for availability and recovery narratives. A licensed firm still examines the rest of the control set. We build the drill and the packet; we do not issue a report.