AWS Backup + AWS Organizations lets you define Aurora PostgreSQL backups once and stamp them into every account. But the org policy won't create your vaults or IAM roles, continuous backup quietly takes over RDS's native backups, Aurora silently ignores cold-storage settings, the default aws/rds key blocks cross-account and air-gapped copies, and your 5-6 year old snapshot will outlive its PostgreSQL version. Here's how we designed around all of it.

Every Aurora cluster has backups turned on from day one. That's the trap: "it's backed up" becomes a sentence nobody verifies.

When you run Aurora PostgreSQL across 80+ AWS accounts, multiple regions, and retention measured in years, the real questions are:

  • Who owns the backup configuration?
  • Where does the copy live if a region goes dark?
  • Can an admin (or an attacker with admin) delete it?
  • Will a seven-year-old snapshot actually restore?

This is part 1 of a series. Part 1 = design. Part 2 covers monitoring and reporting failures. Part 3 covers restores.

Org-wide backup architecture

1. The five nouns of AWS Backup

Noun What it is Where it lives
Vault Encrypted container for recovery points Each member account, each region you back up to
Plan A named bundle of rules Generated in member accounts by the org policy
Rule Schedule + retention + target vault + copy actions + continuous on/off Inside the plan
Selection Which resources get protected (we use a tag) Inside the plan; references an IAM role in the member account
Policy AWS Organizations backup policy that generates the plan Management (or delegated admin) account

Key insight: retention, target vault and replication are per rule, not per plan. The plan is just a container.

2. Account-level vs organization-level settings

Think of it as governing vs holding.

Management account (governs)

# 1. Let AWS Backup act across the organization aws organizations enable-aws-service-access --service-principal backup.amazonaws.com # 2. Turn on the backup policy type on the org root aws organizations enable-policy-type --root-id r-xxxx --policy-type BACKUP_POLICY # 3. Allow cross-account backup copies aws backup update-global-settings --global-settings isCrossAccountBackupEnabled=true 

In the AWS Backup console (Settings), also enable backup policies and cross-account monitoring. If you'd rather not run this from the management account itself, register a delegated administrator for AWS Backup.

Member accounts (hold)

Each account that owns databases needs:

  1. A vault in every region the policy targets (and in the DR region if you copy there).
  2. An IAM role that the policy's selection references, trusted by backup.amazonaws.com.
  3. Aurora opted in for that region:
aws backup update-region-settings --resource-type-opt-in-preference Aurora=true 
  1. The tag on the cluster, e.g. backup-enable = yes.

⚠️ The sentence I wish I'd read on day one: an org backup policy creates the plan in the member account, but not the vault and not the IAM role. If either is missing, the job never starts, and nothing shouts about it.

Policy inheritance

Backup policies attach to the org root, an OU, or a single account, and AWS merges them into an effective policy per account using inheritance operators like @@assign. A common layout:

  • Root: baseline policy (e.g. continuous-only for everything tagged)
  • Production OU: the full ladder with DR copy
  • Specific account: an override, if you really must

You can stop child policies from overriding the parts you care about with @@operators_allowed_for_child_policies. To see what an account actually ended up with:

aws organizations describe-effective-policy --policy-type BACKUP_POLICY --target-id 111122223333 

3. Vaults: standard vs logically air-gapped

Vault types and lock modes

Standard vault

Lives in your own account, encrypted with the KMS key you choose. You can optionally add Vault Lock:

Mode Who can delete early / remove lock Use it for
Governance Principals with the right IAM permissions can bypass Day one, while you tune retention
Compliance Nobody after the grace period (minimum 72 hours): not admins, not root, not AWS Regulated / ransomware-proof retention
resource "aws_backup_vault_lock_configuration" "primary" { backup_vault_name = aws_backup_vault.primary.name min_retention_days = 7 max_retention_days = 2555 # 7 years # Uncomment to switch to COMPLIANCE mode. Omitted = governance mode. # After this grace period the lock is permanent. # changeable_for_days = 3 } 

💡 Start in governance mode, prove your min/max retention against real recovery points, then flip to compliance. A compliance lock with a mistake in it is a mistake you keep.

Logically air-gapped vault

A separate vault type that is always compliance-locked, encrypted with an AWS-owned key by default, and shareable to a recovery account via AWS RAM, even an account in a different organization. The goal is logical separation: owning your production account (or even your org) isn't enough to reach those copies.

Two Aurora-specific notes:

  • Aurora can't back up directly into an air-gapped vault; AWS Backup takes a temporary recovery point in a standard vault and copies it across.
  • Clusters encrypted with the AWS-managed aws/rds key can't be copied into an air-gapped vault. You need a customer-managed KMS key (more on this in the traps section).

4. Continuous (PITR) vs snapshot backups

Continuous (PITR) Snapshot
Restore to Any second in the window The moment it ran
Max retention 35 days Whatever the rule says
Per cluster One continuous recovery point One per scheduled run
Cross-region copy Arrives as a snapshot (no PITR in DR) Copies as a snapshot
Appears in RDS as Automated backups Manual snapshots

The handover nobody tells you about

Once AWS Backup enables continuous backup on an Aurora cluster, AWS Backup takes over Aurora's native automated backups. You can no longer change the backup window or retention from the RDS console or API. In the RDS console, those recovery points are named like continuous:cluster-<job-id>.

Lessons from production:

  • One owner for PITR. Two org policies that both enable continuous backup on the same cluster will conflict. To move a cluster between policies, exclude it from the old policy first (NotResources).
  • Zero jobs can be healthy. A continuous-only plan doesn't create a job per scheduled run once it's set up. An empty job list is not a failure.
  • Full snapshot first. Make sure a full snapshot exists alongside the continuous recovery point before you rely on it.
  • RDS console ≠ AWS Backup status. EarliestRestorableTime on the RDS console reflects native PITR, not your backup policy's activity.

5. Several policies and respective jobs

Protection layers across several regions

Instead of one giant policy that tries to do everything, we can split protection into several org policies, each with a single job and its own tag to opt a cluster in.

Policy Runs in Job Retention idea Leaves the region?
Primary site Primary region (us-east-1) Continuous PITR, the fast "undo" button Short rolling window (days) No
Long-term ladder Primary region Weekly / monthly / yearly snapshots 5 weeks → 1 year → 7 years Every rule copies to a vault in us-west-2
DR site DR region (us-east-2) Weekly / monthly / yearly snapshots of the headless global-database secondary 5 weeks → ~13 months → 7 years Already in the DR region

Why split it this way

  • Independent layers. Tuning the long-term ladder never risks your PITR window, and vice versa.
  • Opt in per layer, by tag. A dev cluster can take PITR only; production takes all three. A new database is protected the moment it's tagged. No ARN lists to maintain.
  • No accidental cross-matching. The DR policy matches a DR-only tag value, so it can never pick up a primary cluster. The primary-site policy uses a different tag key, so it's independent of the ladder.

The selections are the whole trick. Trimmed down, the three policies differ mainly here:

// Primary site policy (us-east-1) "selections": { "tags": { "primary": { "tag_key": { "@@assign": "backup-enable-site" }, "tag_value": { "@@assign": ["primary-only"] } } } } // Long-term ladder policy (us-east-1, copies to us-west-2) "selections": { "tags": { "ladder": { "tag_key": { "@@assign": "backup-enable" }, "tag_value": { "@@assign": ["yes"] } } } } // DR site policy (us-east-2) when you have a DR Global cluster / headless/serverless "selections": { "tags": { "dr": { "tag_key": { "@@assign": "backup-enable" }, "tag_value": { "@@assign": ["dr-e2-only"] } } } } 

A production database ends up with three independent histories: a short PITR window in its own region, long-term snapshots copied to a second region where DR cluster is not available, or a separate snapshot history built in a DR region where there is a DR Global cluster (headless/serverless) from replicated storage. Lose any one region and the other remain.

Click for a trimmed long-term ladder rule with a cross-region copy
{ "plans": { "plan-e1": { "regions": { "@@assign": ["us-east-1"] }, "rules": { "yearly": { "schedule_expression": { "@@assign": "cron(0 5 1 1 ? *)" }, "lifecycle": { "delete_after_days": { "@@assign": "2555" } }, "target_backup_vault_name": { "@@assign": "vault-e1" }, "recovery_point_tags": { "backup-rule": { "tag_key": { "@@assign": "backup-rule" }, "tag_value": { "@@assign": "yearly" } } }, "copy_actions": { "arn:aws:backup:us-west-2:$account:backup-vault:vault-w2": { "target_backup_vault_arn": { "@@assign": "arn:aws:backup:us-west-2:$account:backup-vault:vault-w2" }, "lifecycle": { "delete_after_days": { "@@assign": "2555" } } } } } }, "selections": { "tags": { "ladder": { "iam_role_arn": { "@@assign": "arn:aws:iam::$account:role/org-backup-role" }, "tag_key": { "@@assign": "backup-enable" }, "tag_value": { "@@assign": ["yes"] } } } } } } } 

$account is substituted with each member account's ID, so one policy works everywhere. An empty lifecycle on a copy action means the copy inherits the source rule's retention. Set it explicitly only when the remote copy should live longer or shorter than the original.

Watch out when you split

  • Only one policy should own PITR. Continuous backup can be enabled in more than one policy. If a cluster carries tags that match two policies with enable_continuous_backup: true, two plans claim the single continuous recovery point a cluster is allowed. Pick the owner (we use the primary-site policy) and keep continuous off everywhere else.
  • Tag recovery points. Every rule stamps backup-policy and backup-rule tags on what it creates, so during an incident someone can filter for "the yearly from January" instead of guessing from timestamps.
  • Next up: air gap. A logically air-gapped copy in a separate recovery account is the next layer, for backups that must survive even a compromised organization.

6. Backing up a headless/serverless DR cluster

Headless DR with region-local backups

With Aurora Global Database, the primary region replicates to a secondary region at the storage layer. A headless secondary is that cluster with zero DB instances: storage keeps up, compute costs nothing until you need it. In our tests, adding an instance to a headless cluster took under 10 minutes.

Instead of copying every snapshot across regions, we point the DR-site policy at the headless cluster itself, in us-east-2. The DR region builds its own backup history from its own replicated storage, with no cross-region copy charges, and becomes a genuinely separate recovery site.

Creating a headless Aurora PostgreSQL secondary (the console can't do zero instances for PostgreSQL):

aws rds create-db-cluster \ --region us-east-2 \ --db-cluster-identifier mydb-e2 \ --global-cluster-identifier mydb-global \ --engine aurora-postgresql \ --engine-version 16.4 \ --db-subnet-group-name mydb-subnets-e2 \ --vpc-security-group-ids sg-0123456789abcdef0 \ --storage-encrypted \ --kms-key-id arn:aws:kms:us-east-2:111122223333:key/your-cmk-id 

Gotchas:

  • No burstable classes (db.t3, db.t4g) in a global database. Your emergency instance is r- or m-class.
  • Separate Terraform state for DR backup infra. Running the same backup module from the same directory for a second region will plan to destroy the first region's vault, and the account-global IAM role will collide with EntityAlreadyExists.
  • On PostgreSQL, creating and deleting secondary readers can affect vacuum on the primary; watch it after DR tests.

7. The traps that show up years later

🕰️ Trap 1: Your yearly backup will outlive its PostgreSQL version

A 5-6 year old snapshot taken on today's major version will almost certainly be restored (if ever) after that version leaves standard support. When that happens, Aurora tries to upgrade the snapshot during restore to a version still in standard support. If that fails, it enrolls the restored cluster in RDS Extended Support, which is billed.

What we do about it:

  • Know what you're holding. We tag every cluster with Engine and EngineVersion when it's enrolled (section 7b), and snapshots record their engine version too:
aws rds describe-db-cluster-snapshots --query "DBClusterSnapshots[].[DBClusterSnapshotIdentifier,EngineVersion,SnapshotCreateTime]" --output table 
  • Yearly restore drill. Restore the oldest long-term snapshots, upgrade them, and confirm the data is usable, before an auditor asks.
  • Logical safety net. For archives that truly matter, keep a pg_dump alongside the snapshot. A dump doesn't care which engine version produced it.

🧊 Trap 2: Cold storage settings that silently do nothing

A rule can say move_to_cold_storage_after_days: 30, and the policy will happily accept it. It looks like a cost win. But AWS Backup's cold tier covers services like EBS, EFS and DynamoDB, not Aurora, and AWS Backup ignores the transition for resource types that don't support it. No error, no warning: seven years of yearlies stay at warm-storage prices.

If you see cold-storage settings in a policy that only selects Aurora clusters, they're documentation, not behavior. If long-term cost matters, a pg_dump in S3 with a lifecycle rule to Glacier is the real cheap archive (and doubles as the Trap 1 safety net).

🔑 Trap 3: The default KMS key blocks your exit doors

Clusters encrypted with the AWS-managed aws/rds key can't be shared or copied to another account, and can't be copied into a logically air-gapped vault. Use a customer-managed key from day one. Changing an existing cluster's key means snapshot → copy with new key → restore.

🏚️ Trap 4: Missing vaults fail silently

The org policy happily creates a plan that targets a vault that doesn't exist. Audit every member account:

aws backup list-backup-vaults --query "BackupVaultList[].BackupVaultName" 

⏱️ Trap 5: "Last runtime" is not success

The console's last-runtime timestamp moves when the scheduler evaluates the plan, not when a job succeeds. Real health comes from job states, which is exactly what Part 2 is about.

What's next

  • Part 2 — Monitoring & reporting: EventBridge + SNS for failures, and consolidating AWS Backup reports from every account into one queryable place.
  • Part 3 — Restores: snapshot vs point-in-time restores, the parameter-group gotcha, and a scripted, interactive restore flow.

If you run Aurora at scale, which trap got you first? Drop it in the comments 👇

Further reading