Use this page for a backup coverage audit, a disaster-recovery exercise, or before any risky data change. A backup you have never restored is a hope, not a backup.
Define the policy per data class
Example starting point; replace the numbers with your own.
| Data class | RPO (max data loss) | RTO (max downtime) | Retention | Copy |
|---|---|---|---|---|
| Production transactional DB | 5 min (point-in-time) | 1 h | 35 days plus monthly for 1 year | cross-region and cross-account |
| Production object storage | 24 h | 4 h | versioning plus lifecycle | cross-region replication |
| Non-production | 24 h | 1 day | 7 days | none |
Retention may be set by regulation. Check before shortening anything.
Audit coverage with tags (read-only)
# Which RDS instances have automated backups and how long?
aws --profile <readonly-profile> --region <region> rds describe-db-instances \
--query 'DBInstances[].{id:DBInstanceIdentifier,retention:BackupRetentionPeriod,encrypted:StorageEncrypted}' --output table
# What AWS Backup protects
aws --profile <readonly-profile> --region <region> backup list-protected-resources \
--query 'Results[].{arn:ResourceArn,type:ResourceType,last:LastBackupTime}' --output table
# Buckets without versioning
for b in $(aws --profile <readonly-profile> s3api list-buckets --query 'Buckets[].Name' --output text); do
v=$(aws --profile <readonly-profile> s3api get-bucket-versioning --bucket "$b" --query Status --output text 2>/dev/null)
[ "$v" = "Enabled" ] || echo "$b versioning=$v"
done
- Every production data store appears in the protected list.
- A
backuptag on each resource matches a backup plan selection rule. - Backup vaults use a separate key and, ideally, a separate account with vault lock.
Restore test runbook
Run at least quarterly per critical store.
- Pick a recovery point (not the newest one; pick something a week old).
- Restore into an isolated, non-production network with a new name.
- Check: it starts, row counts or object counts are in the expected range, the application can read it.
- Record the time it took. That is your real RTO.
- Delete the restored copy.
- Write the result in the ticket, with dates and durations.
# Example: restore an RDS snapshot into a test name (a write; needs approval)
aws --profile <restore-role-profile> --region <region> rds restore-db-instance-from-db-snapshot \
--db-instance-identifier <db>-restore-test-$(date +%Y%m%d) \
--db-snapshot-identifier <snapshot-id> \
--db-subnet-group-name <isolated-subnet-group> --no-publicly-accessible
Pitfalls
- Backups in the same account as production. A compromised account loses both.
- Encrypted backups whose KMS key can be deleted by the same admins.
- Restore tests that restore into production networks and accidentally connect to live consumers.
- Treating replication as backup. Replication copies deletes and corruption too.