The situation
The platform team runs forty AWS accounts under one AWS Organization: twenty-eight production workload accounts (EC2 and EBS, RDS for PostgreSQL, Aurora, DynamoDB, EFS, S3), six data-platform accounts, three shared-services accounts, and three security and audit accounts. One of those three is a recovery account stood up for this mandate, isolated from everything else and reachable only by the backup-ops team under a break-glass process. The primary Region is ap-southeast-2; the nominated second Region is ap-southeast-4.
The board memo, written after a peer firm was ransomed, says plainly: “Assume the production account has been fully compromised. An attacker holds valid AdministratorAccess. What stops them deleting the backups?” Compliance turned that into six requirements. Immutability against deletion even with admin credentials. Storage in a separate account with separate IAM. A copy in a second Region. Seven-year retention. Central management across forty accounts. Audit reporting that names the controls and lists which resources passed or failed each one.
What actually matters
The threat model is admin credentials inside a production account, so anything an IAM policy in that account can change is not protection. The same principal that reads the data can rewrite the policy guarding it, and can do both in one session. The authoritative copy has to live in an account administered by a different team, with no role in any production account that recovery-account principals trust and no assume-role path running the other way. That is a structural boundary rather than a policy one, and it is the only kind the memo’s assumption leaves standing.
Immutability then has to come from the service rather than from a permission. A locked vault denies deletes and lifecycle changes on its recovery points from every user including the account root from the moment the lock is applied. The grace period applies to the lock rather than to the recovery points: until it expires the lock can still be removed or reconfigured, and after it expires neither any user nor AWS can lift it while the vault holds recovery points. Governance mode is removable by anyone holding the right IAM permission at any point, which answers a different requirement entirely. And closing an account that holds a locked vault suspends it for 90 days, after which AWS deletes the vault contents whether it is locked or not. The recovery account needs protecting as an account, not only as a vault.
Seven calendar years is 2,557 days once leap days are counted, and the 2,555 that 7 × 365 produces falls two days short of the obligation. A lifecycle value in a plan is also a number an administrator can edit next quarter, whereas Vault Lock’s minimum and maximum retention reject any backup or copy job whose retention falls outside the window. That moves the number out of the plan and into the vault. It also fixes the bill for seven years: every copy kept that long is another seven years of storage. Which account pays the transfer depends on the resource type, because AWS Backup bills data transfer to the source account for resource types it fully manages and to the destination account for every other type. Most of this estate sits in the second group, so the security OU carries the transfer line as well as the storage line, which is worth saying out loud before finance asks why.
Two properties the mandate does not name decide whether any of it works. AWS Backup does not restore across accounts, so a recovery point sitting safely in the recovery account cannot be restored into production; it has to be copied back first and restored where it lands. And a copy can be perfectly immutable and still useless, because ransomware that dwelled for a fortnight is inside every recovery point taken during that fortnight. Durability and cleanliness are different guarantees, and the mandate only asks for one of them.
What we’ll filter on
- Immutability enforced by the service, outside the reach of any production credential.
- Storage in an account whose IAM is administered by a different team.
- A copy in a second Region, for every resource type in the estate.
- Retention fixed at 2,557 days, with shorter retention refused rather than discouraged.
- One policy at the Organizations layer that new accounts inherit as they are vended.
- Per-resource evidence a regulator can read, and a tested route back into production.
The landscape
AWS Backup. A managed cross-service backup service covering EBS and EC2, RDS, Aurora, DynamoDB, EFS, FSx, S3, Storage Gateway, DocumentDB, Neptune, Redshift, Timestream, SAP HANA on EC2, CloudFormation stacks, EKS, and virtual machines through Backup gateway. A plan carries a schedule, a lifecycle, a destination vault and optional copy actions. Backup policies sit at the Organizations layer and push plans into member accounts from a delegated administrator. Vault Lock supplies WORM semantics, and Backup Audit Manager reports control by control on top of AWS Config.
Logically air-gapped vaults. A second vault type, with compliance-mode Vault Lock always on, recovery points held in an AWS Backup service-owned account rather than in the vault owner’s storage, an AWS owned key by default, and sharing to named accounts through AWS RAM so another account can restore straight from the vault. Copies into one are made by the account that owns it; accounts it is shared with can view and restore but cannot copy in. A single central air-gapped vault in the recovery account therefore cannot be the destination for a production account’s copy action. Minimum retention is seven days.
Service-native snapshots. Every service exposes its own primitive, with Data Lifecycle Manager scheduling the EBS ones. That is one control plane, one IAM surface and one retention setting per service, and nothing that attaches at the Organizations layer.
S3 Object Lock with replication. For the object estate this is WORM enforced by S3 itself, with a compliance mode of its own and replication to a bucket in another account and Region. It covers objects and nothing else, so it answers one row of a six-row estate.
Scripted snapshots and third-party platforms. A Step Functions machine calling service APIs can be made to do all of this, with immutability and reporting built by hand and maintained by whoever wrote it. A data-protection vendor (Veeam, Clumio, Cohesity, Rubrik, Commvault) is the right pick when the estate spans clouds or when the vendor’s detection features are themselves the requirement. Here it adds a vendor and a subscription to a mandate AWS-native services already satisfy.
Evaluation
Side by side
| Mechanism | Service-enforced immutability | Separate account | Cross-Region | Whole estate | Org-wide policy | Reporting |
|---|---|---|---|---|---|---|
| AWS Backup: plan, cross-account copy, compliance-mode Vault Lock | ✓ | ✓ | ✓ | ✓ (DynamoDB needs advanced features) | ✓ | ✓ |
| Logically air-gapped vault | ✓ | ✗ (owner copies in) | ✓ | Partial | ✓ | ✓ |
| Service-native snapshots and DLM | ✗ | Partial | Partial | ✗ | ✗ | ✗ |
| S3 Object Lock with replication | ✓ | ✓ | ✓ | ✗ (objects only) | Partial | Partial |
| Scripted snapshots | Hand-built | ✓ | ✓ | ✓ | ✓ | ✗ |
| Third-party platform | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Two rows clear every column: AWS Backup inside the AWS-native world, and the vendor row. The mandate is AWS-only, so AWS Backup lands. The air-gapped vault clears immutability without clearing separate-account ownership, because the vault owner is the only account that can write into it, so it belongs alongside the recovery-account copy rather than instead of it.
Matching the mandate to the primitives
The solution
What only the management account can do
The cross-account management switches in AWS Backup settings can only be thrown with management-account credentials, and three of them carry this design: backup policies, cross-account monitoring, and cross-account backup. A copy action naming a vault in another account is rejected until cross-account backup is enabled, and nothing in the policy says so. Registering delegated administrators is management-account work too, up to five accounts.
Register the security-OU account with aws organizations register-delegated-administrator --account-id <sec-acct> --service-principal backup.amazonaws.com. Registration on its own grants cross-account job monitoring and no more. Two further steps turn it into a policy administrator: attach the AWSBackupOrganizationAdminAccess managed policy inside that account, which does not happen automatically, and create a resource-based delegation policy for backup policies in the Organizations console. Skip either and the delegated administrator can watch jobs it cannot configure.
The groundwork in each member account
A backup policy names a vault, a Region and an IAM role; it does not create them. An account that receives the policy without a vault in the named Region, a role AWS Backup can assume, and a customer-managed KMS key protects nothing, and the gap surfaces as an absence rather than an error. CloudFormation StackSets with service-managed permissions and automatic deployment to the OU is how the vault, role and key arrive ahead of the policy, and how a newly vended account has them on day one.
The policy
A backup policy is JSON shaped like a declarative Organizations policy. It attaches to an OU, inherits down the tree, and embeds plans whose rules carry schedule, lifecycle and copy actions.
{
"plans": {
"RansomwareResiliencePlan": {
"regions": { "@@assign": ["ap-southeast-2"] },
"rules": {
"DailyBackup": {
"schedule_expression": { "@@assign": "cron(0 18 * * ? *)" },
"target_backup_vault_name": { "@@assign": "prod-local-vault" },
"start_backup_window_minutes": { "@@assign": "60" },
"lifecycle": { "delete_after_days": { "@@assign": "35" } },
"copy_actions": {
"arn:aws:backup:ap-southeast-2:REC-ACCT:backup-vault:recovery-syd": {
"target_backup_vault_arn": {
"@@assign": "arn:aws:backup:ap-southeast-2:REC-ACCT:backup-vault:recovery-syd"
},
"lifecycle": { "delete_after_days": { "@@assign": "2557" } }
},
"arn:aws:backup:ap-southeast-4:REC-ACCT:backup-vault:recovery-mel": {
"target_backup_vault_arn": {
"@@assign": "arn:aws:backup:ap-southeast-4:REC-ACCT:backup-vault:recovery-mel"
},
"lifecycle": { "delete_after_days": { "@@assign": "2557" } }
}
}
}
},
"selections": {
"resources": {
"StatefulResources": {
"iam_role_arn": { "@@assign": "arn:aws:iam::$account:role/OrgBackupRole" },
"resource_types": {
"@@assign": [
"arn:aws:ec2:*:*:volume/*",
"arn:aws:ec2:*:*:instance/*",
"arn:aws:rds:*:*:db:*",
"arn:aws:rds:*:*:cluster:*",
"arn:aws:dynamodb:*:*:table/*",
"arn:aws:elasticfilesystem:*:*:file-system/*",
"arn:aws:s3:::*"
]
}
}
}
}
}
}
}
Selection is by resource type rather than by tag, and that is a threat-model decision rather than a style one. A tag-based selection reads a label the production administrator can remove, so under the memo’s assumption coverage could be switched off one UntagResource call at a time, with nothing but the next report to show it had happened. Resource-type patterns leave nothing in the production account to edit. $account resolves to each member’s own account ID, so one policy serves all twenty-eight.
The local vault keeps 35 days because the in-account copy is the fast operational restore, not the record. Seven years in all three vaults would triple the storage line for no extra protection, since the copies are independent recovery points and deleting the local one leaves them intact. A rule allows up to five copy actions, so two leaves room for an air-gapped vault later.
One cost consequence follows from the key change. An EBS snapshot copied into a vault that uses a different KMS key is copied in full rather than incrementally, and the recovery-account vaults use their own keys by necessity, so every daily EBS copy carries the whole volume rather than the day’s changed blocks. Across twenty-eight accounts that is the largest line in the design, and it should be modelled before the mandate is signed off rather than after the first invoice. The RDS copies carry a smaller trap: a cross-Region copy uses the destination Region’s default option group, so a custom group with persistent options fails the copy job unless the same group already exists there.
The recovery account
The vault access policy in the recovery account allows exactly one cross-account action, backup:CopyIntoBackupVault, scoped with a condition on aws:PrincipalOrgID so a new production account needs no policy edit. AWS Backup rejects every other cross-account action against a vault regardless of what the policy says, which makes that grant narrow by construction. The source side needs its own half: an IAM role in the production account carrying both backup:CopyFromBackupVault and backup:CopyIntoBackupVault, which the AWSBackupServiceRolePolicyForBackup managed policy already includes. The destination vault also needs a key the source account can be granted use of, which for most of this estate means a customer-managed key rather than the aws/backup key a default vault carries.
Then the lock, per Region:
aws backup put-backup-vault-lock-configuration \
--backup-vault-name recovery-syd \
--min-retention-days 2557 \
--max-retention-days 2922 \
--changeable-for-days 7
Compliance mode is selected by supplying --changeable-for-days. Omit it and the same command produces a governance-mode lock that any principal with backup:DeleteBackupVaultLockConfiguration can remove, which is the single most consequential flag in this design. The grace period must be at least three days and at most 36,500; seven gives the team a week to find a mistake. After that the lock cannot be changed or removed by any user, by the account root, or by AWS.
The retention window does the enforcing. A backup or copy job whose lifecycle retention is shorter than 2,557 days fails outright rather than landing with a shorter clock, so nobody can halve the obligation by editing the plan. The maximum of 2,922 days matters for the opposite reason: a rule that writes recovery points with no expiry produces storage that survives the grace period and can never be deleted or reduced, and that is a bill with no off switch.
Two service control policies close the remaining gaps. A destination account that leaves the organisation keeps the backups it holds, so deny organizations:LeaveOrganization on the recovery account. And a compromised production account could copy recovery points to a vault it controls, so deny backup:CopyFromBackupVault from the production OU unless backup:CopyTargets matches the two approved vault ARNs.
Why production credentials do not reach it
An attacker with AdministratorAccess in a production account can delete every recovery point in the local vault and the plan that creates them. That destroys the working copy and the schedule, and leaves the copies already in the recovery account untouched. There is no role there that trusts a production principal, and the one cross-account grant permits writing into the vault rather than reading, listing or deleting. If a path were somehow found, compliance-mode Vault Lock denies the delete anyway. The key protecting the copy is a customer-managed key in the recovery account that no production principal appears in.
The route back
AWS Backup does not restore across accounts. Recovery means copying the chosen recovery point from the recovery-account vault into whichever account will run the restore, then restoring it there. The recovery account initiates that copy, so its role needs backup:CopyFromBackupVault and the receiving vault needs a policy allowing CopyIntoBackupVault, and the receiving account needs the service-linked role for the resource type before the restore will start. A first cross-account copy is a full copy rather than an incremental one, so a large volume crossing a Region boundary is measured in hours. That figure is the part of the recovery time objective nobody has, and restore testing does not supply it: a restore testing plan starts restore jobs from vaults the testing account can already reach and times the restore, not the copy that has to precede it. Timing the copy-back means running one on demand, out of the recovery account and into the account that will restore, and writing down how long it took, the same way the DR exercise becomes a scheduled test rather than a document.
The KMS piece, which is easy to miss
A copy is encrypted with the key of the destination vault, and which keys are legal depends on how fully AWS Backup manages the resource type. Of this estate only EFS, S3 and DynamoDB with advanced features enabled are fully managed. For EC2, EBS, RDS and Aurora the recovery point in the source vault inherits that resource’s own encryption, and a cross-account copy of one of those cannot use an AWS managed key at all, because an AWS managed key policy is immutable and cannot be shared with another account.
That turns a backup requirement into an encryption programme. Every EBS volume, RDS instance and Aurora cluster in scope has to be encrypted with a customer-managed key whose policy grants the recovery account kms:Decrypt, kms:GenerateDataKey and kms:CreateGrant, and unencrypted Aurora clusters produce unencrypted copies. The destination vault key needs the same three permissions for the copy path. A gap on either side produces a failed copy job rather than a corrupt one, so the symptom is a recovery point that never appears. One key per Region in the recovery account, with grants keyed on aws:PrincipalOrgID, keeps the key policy static as accounts are added.
Two resource types need checking before anyone promises the second Region. Plain DynamoDB supports no copy operation at all, in-Region or cross-Region, until AWS Backup advanced features are enabled for DynamoDB in that Region; RDS Multi-AZ DB clusters support no copy operations either. Both are estate changes with their own change windows, and both sit on the critical path for this mandate.
A clean copy, not only a durable one
Amazon GuardDuty Malware Protection for AWS Backup scans a recovery point after each backup completes. A scan_actions block on the rule sets the scan mode, and scan_settings on the plan names the scannable resource types and a scanner role trusting malware-protection.guardduty.amazonaws.com. The first scan of a resource is always full and later ones can be incremental, and each job reports NO_THREATS_FOUND or THREATS_FOUND through the AWS Backup console and EventBridge. Recovery then starts from the last clean recovery point rather than the newest one. GuardDuty bills the scanning, not AWS Backup. Coverage runs to EC2, EBS and S3, so how far back to go for the relational half stays a judgement call made during the incident.
The reporting
Backup Audit Manager evaluates controls through AWS Config, so resource tracking has to be turned on first. Two meters then run: AWS Backup charges per control evaluation, meaning one resource weighed against one control, and AWS Config charges for every configuration item it records. A framework for this mandate collects the controls that match the six requirements:
BACKUP_RESOURCES_PROTECTED_BY_BACKUP_PLANBACKUP_PLAN_MIN_FREQUENCY_AND_MIN_RETENTION_CHECKBACKUP_RECOVERY_POINT_MINIMUM_RETENTION_CHECKBACKUP_RECOVERY_POINT_ENCRYPTEDBACKUP_RECOVERY_POINT_MANUAL_DELETION_DISABLEDBACKUP_RESOURCES_PROTECTED_BY_CROSS_ACCOUNTBACKUP_RESOURCES_PROTECTED_BY_CROSS_REGIONBACKUP_RESOURCES_PROTECTED_BY_BACKUP_VAULT_LOCK
The framework has to exist in each member account, not only in the delegated administrator, or the report shows nothing for the accounts that lack one. StackSets again, and the same fifteen-frameworks and fifty-controls-per-Region limits apply in each of them. The report plan itself lives in the delegated administrator and delivers to an S3 bucket in that account, because cross-account bucket delivery is not supported; the regulator gets read access to a prefix rather than a copy by email. A report covering other accounts arrives as CSV, with JSON available only for a report scoped to the report plan’s own account and Region, which is worth knowing before anyone builds a JSON parser. Reports land daily, with an on-demand run available when a date is needed.
One wrinkle from the Region pair: ap-southeast-4 requires account opt-in, and in an opt-in Region a delegated administrator can launch backup policies but does not get the cross-account monitoring view. The Melbourne side of this estate is watched from the management account.
What’s worth remembering
- A grace period selects compliance mode. Supply at least three days; once it expires, nobody including AWS can remove or weaken the lock.
- Seven years is 2,557 days. Set it as the vault’s minimum and maximum retention, not only in a plan someone can edit.
- Member accounts need groundwork first. Cross-account backup is a management-account switch; each member then needs a vault, role and shareable customer-managed key.
- Check DynamoDB and Multi-AZ clusters. Plain DynamoDB and RDS Multi-AZ DB clusters support no copy operation, so verify before promising a second Region.
- Restores need a copy back first. AWS Backup does not restore across accounts, and restore testing times the restore, not that copy.
- Immutable is not clean. Ransomware that dwelled before the backup sits in every later recovery point; malware scanning finds the last clean one.