---
title: AWS account and resource decommissioning
slug: aws-account-and-resource-decommissioning
summary: How to prove something is unused, retire it in reversible stages and close an AWS account without breaking a hidden dependency.
order: 16
updated: 2026-11-11
status: ready
---

Use this page for retiring a stack, a service, a VPC, a set of resources or a whole account. Decommissioning saves money and shrinks the attack surface, but deleting something that was quietly in use causes an outage you cannot easily undo.

## Stage it: prove, isolate, wait, delete

```mermaid
flowchart LR
  P[Prove unused] --> O[Owner signs off]
  O --> S[Scream test: disable or isolate]
  S --> W[Wait 2-4 weeks]
  W --> B[Final backup or snapshot]
  B --> D[Delete via IaC MR]
  D --> C[Close account if empty]
```

## Prove it is unused

- [ ] Traffic: load balancer and API gateway request counts for 30 days.
- [ ] Compute: CPU and network on instances and tasks; Lambda invocations.
- [ ] Data: database connections, S3 request metrics or access logs, queue message counts.
- [ ] Callers: CloudTrail for API calls into the resources from other accounts or roles.
- [ ] Network: VPC flow logs, peering and transit gateway attachments, routes that point into this VPC.
- [ ] DNS: records in any zone that point at these resources.
- [ ] Code and config: search repos and CI for names, ARNs and hostnames.
- [ ] Scheduled jobs and EventBridge rules that target these resources.

Recipes for each are in [AWS read-only investigation](./aws-read-only-investigation.md). Write the evidence into the ticket as a table.

## Rate the risk of each piece

| Piece | Risk | Why |
| --- | --- | --- |
| Stopped instances, unattached volumes, old snapshots | Low | Nothing routes to them |
| Sandbox stacks, unused DNS names | Low | Non-production |
| Parameters and secrets | Medium | Something may read them at start-up |
| Route tables, subnets, peering, transit attachments | High | Other networks may route through them |
| Databases and buckets with data | High | Data loss is permanent; check retention rules |

Do the low-risk pieces first, as separate tickets.

## Scream test

- [ ] Stop instances, scale services to zero, detach a route, or deny access with a policy, rather than deleting.
- [ ] Announce the date and who to contact.
- [ ] Wait long enough to cover monthly jobs and month-end reporting.

## Delete

- [ ] Final snapshot or export where retention rules require it, tagged with the ticket and a delete-after date.
- [ ] Remove through Terraform in an MR (see [Terraform changes](./terraform-changes-via-merge-request.md)). For resources not in code, write the exact CLI commands into the MR or ticket for review first.
- [ ] Remove DNS records, monitors, dashboards, alerts and CI jobs that referenced it.

## Close an AWS account

- [ ] Account is empty of billable resources in every region (check Cost Explorer for the last 30 days by service).
- [ ] No one still uses it for log archives, backups or cross-account roles.
- [ ] Root user email and MFA are under team control.
- [ ] Close through AWS Organizations by the organization admin. The account is suspended for 90 days, then permanently closed; it can be reopened during that window.
- [ ] Remove it from SSO assignments, inventories, monitoring and the account list.

## Pitfalls

- "Suspended" is not "closed". Track the account until the 90 days pass.
- Deleting the KMS key that encrypts backups you kept. Schedule key deletion last, with the longest waiting period.
- Assuming a sandbox name means sandbox. Check what actually routes to it.
- Quarantined or legal-hold accounts are out of scope until someone with authority says otherwise.
