What you'll be able to decide
Whether a system runs in one AWS account or in several; where each wall goes (per environment, per workload that can hurt another, per client, and a backup account production can't write over); what each wall stops; and how to cross one on purpose.
An account is the hardest wall AWS has: two accounts can't touch each other unless someone allows it. Inside one account, only IAM policies stand between a leaked key or a wrong command and production, and some limits are shared by everything in it: Lambda's concurrency pool, SES's sending reputation. So put a wall wherever one thing must not be able to hurt another: production apart from dev and staging, a workload that can damage a shared limit in its own account, a client's systems in the client's accounts, and the backups in an account production can't write over. Organizations costs nothing extra and Savings Plans still apply across the accounts, so the cost of the walls is setup, not the bill.
In short
The options
A. One account, careful policies
Every environment and workload side by side, told apart by names and tags. Everything rests on every IAM policy being exactly right.
B. An account per environment
An empty management account, then dev, staging and prod in accounts of their own, with one sign-in for people. A mistake or a leaked key in one can't touch the others.
C. An account per workload, and per client
A workload that can damage a limit it shares with the others, such as email reputation, in its own account; and each client's systems in the client's own accounts.
D. A backup account
A copy of every recovery point in a locked vault, in an account the production credentials can't reach.
The rule of thumb
An account is the hardest wall AWS has. Inside one account, everything rests on every IAM policy being exactly right.
How the answer changes with scale
One app and a small team
A management account, an account each for dev, staging and prod, and a backup account. Organizations costs nothing extra, so being small is no reason to share one.
A workload that can damage a limit it shares with another
An account of its own: marketing mail apart from sign-in mail.
Teams that pay their own bills
Restrict each Savings Plan to the account that bought it, or group accounts with Cost Categories.
Dozens of accounts, vended by a central security team
Control Tower earns its place, with AWS's prebuilt controls. Below that, Organizations, a handful of SCPs and Identity Center in code.
The problem, in plain words
Inside one AWS account, everything can reach everything else unless a policy says no. The production database, the staging API, a developer's experiment and last night's backups sit side by side, and the only thing between them is IAM: every policy, on every role and every user, exactly right. That's the hardest part of AWS to get right. Getting policies least-privilege by hand was a nightmare for years, and today they're largely the agent's problem, with a human reviewing the result. One wrong policy still reaches everything in the account.
An account also shares its limits. Lambda's concurrency is one pool for every function in the account and Region. SES's sending reputation is per account and region. So a job in staging can throttle production, and a newsletter can stop the password resets.
An account is the one wall that doesn't depend on a policy being right: two accounts can't touch each other unless someone allows it. So the question isn't "how careful are our policies?" It's where the walls go.
The picture
The same two accidents, three ways: a developer's key that leaks, and production credentials that get stolen.
One account
- Leaked developer key
- One account: dev, staging and prod
- Production data
- Production's secrets
- The backups
Everything rests on every IAM policy being exactly right.
An account per environment
- Leaked developer key
- The damage stays in the dev account
- Reach into production
Two accounts can't touch each other unless someone allows it.
A backup account
- Stolen production credentials
- Production data deleted
- Locked vault in the backup account
- Restored
A copy production can't write over survives ransomware and a fat-fingered admin.
The options
One account, with careful policies. Everything in one place, told apart by names and tags. I don't build anything a client depends on this way. Everything rests on every IAM policy being exactly right, the limits are shared, and the backups sit within reach of the credentials they're meant to survive. The alternative costs nothing extra: AWS Organizations and IAM Identity Center have no extra charge.
An account per environment. My default, and non-negotiable on every AWS engagement. This is how I wire it:
- A management account that holds nothing but Organizations, Identity Center and the bill.
- An account each for dev, staging and prod, so a mistake or a leaked key in one can't touch the others.
- A few service control policies (SCPs): nobody leaves the organization, nobody turns off CloudTrail, nothing runs outside the Regions the client uses.
- One sign-in for every person through Identity Center, with permissions per account and short-lived credentials. No access keys anywhere.
The code follows the walls. Pulumi has one project per app and one stack per environment, and the pipeline deploys each environment with its own OIDC role in its own AWS account (GitHub Actions). When I moved an agriculture-technology platform off a single server (the project), it landed on accounts separated by environment, with single sign-on instead of shared passwords.
An account per workload, and per client. Some limits belong to the whole account, and some of them can't be fixed inside it. SES's reputation is one of those: at 5% bounces or 0.1% complaints the account goes under review, and at 10% or 0.5% AWS can pause sending, for every app in it. So marketing goes in a separate account from transactional mail, and a campaign can't take down sign-in. Where a shared limit does have a fix inside the account, use it: Lambda's pool has reserved concurrency, capacity no other function can take.
Per client is the same wall, one level up. A client's accounts sit under the client's own organization, with one bill and one set of guardrails. Everything I build is in the client's AWS accounts and repositories, documented, so their team can take it over. Splitting doesn't cost the discounts either: Savings Plans and Reserved Instances apply across every account in the organization, and Cost Explorer splits the bill by account.
A backup account. The account that survives the others. AWS Backup copies every recovery point into a locked vault in a separate account. The separate account matters more than the second Region: ransomware and a fat-fingered admin both start with credentials in the production account, and a copy in another account, in a vault even the root user can't empty, survives both. Cross-account copies only work inside one organization, one more reason the organization comes first. RDS point-in-time restore doesn't copy to another account, so plan two recovery points: point-in-time restore in production for "undo the last hour", and daily snapshot copies in the backup account for "the account is gone".
The one account with no wall above it. SCPs don't apply to anyone in the management account. Whatever runs there escapes every guardrail you write. Don't put a workload there, however small: keep it to Organizations, Identity Center and billing.
A concrete scenario
A Sydney company runs a booking platform on AWS. Its contracts keep customer data in Australia, so its email goes through SES in Sydney. Everything is in one account: dev, staging and prod told apart by name prefixes, an IAM user key on each developer's laptop, password resets and the monthly newsletter sent from the same account, and the database's snapshots next to the database.
| What goes wrong | In one account | Behind walls |
|---|---|---|
| A developer's laptop key leaks | It's as far from the production database as one IAM policy | It reaches the dev account at most. With Identity Center, there's no long-lived key to leak in the first place |
| The newsletter goes to a badly imported list | Bounces pass 5% and the account goes under review; at 10%, AWS can pause sending, password resets included | The marketing account is paused. Sign-in mail keeps going from production |
| A reprocessing job in staging floods Lambda | It drains the pool production's API draws on: 1,000 concurrent executions by default, shared by the whole account and Region | Staging has a pool of its own. In production, reserved concurrency guards the functions that matter most |
| An admin's production credentials are stolen | The snapshots are in the same account, within reach | The copies sit in a locked vault in the backup account |
| A Savings Plan is bought for production | One account, one bill: nothing to split | Still one bill. The discount floats to any account by default; restrict it if teams pay their own |
None of these needed a new service. They needed walls: an empty management account, three environment accounts, one for marketing mail and a backup account, under one organization, on one bill.
The trade-offs
| One account | An account per environment | Per workload and client | A backup account | |
|---|---|---|---|---|
| What a leaked key reaches | Whatever the policies didn't forbid | Its own environment | Its own workload | Not the copies: production's credentials can't write over them |
| Shared limits (Lambda's pool, SES's reputation) | Shared by everything | One set per environment | One set per workload | Not applicable |
| What it takes | Nothing to set up; every policy right, forever | An organization (no extra charge), each account in code | More accounts to switch between | A customer-managed KMS key shared with it, and a dedicated vault |
| Crossing a wall | There's no wall | A grant you write: a role, a key policy | The same | Copies only inside one organization |
| The bill | One line | Split by account; Savings Plans apply across every account | The same, with plans restricted where teams pay their own | One more account on the same bill |
The rule of thumb
Put a wall wherever one thing must not be able to hurt another. An account is the hardest wall AWS has; inside one, everything rests on every IAM policy being exactly right. So production lives alone. A workload that can break a limit it shares gets its own account. A client's systems live in the client's accounts. The backups live where production's credentials can't reach them. And the management account stays empty, because it's the one account no guardrail applies to.
When the answer changes with scale
- One app, a small team: a management account, dev, staging and prod, and a backup account. Organizations and Identity Center cost nothing extra, so being small is no reason to share one account.
- A second workload that can hurt the first: its own account. Marketing mail is the classic case, because SES's reputation can't be split inside an account.
- Teams that pay their own bills: by default the discount floats to any account in the organization, so the plan bought for production can end up discounting someone's test cluster. Restrict the plan to the buying account, or group accounts with Cost Categories. Turn Cost Explorer on in the management account, with the accounts and environment tags activated from day one.
- Past ten accounts: a new organization can hold 10 accounts by default, and a closed account keeps counting until it's permanently closed, 90 days later. Request the increase from the management account before the plan needs it.
- Dozens of accounts, vended by a central security team: that's when Control Tower earns its place, with AWS's prebuilt controls. I haven't needed it. For my clients' size, Organizations, a handful of SCPs and Identity Center in code do the same job with less machinery.
Crossing a wall on purpose
A wall is only worth it if every crossing is deliberate. These are the ones that catch people:
- Your own keys, from day one. A secret encrypted with the default aws/secretsmanager key can't be shared with another account, and cross-account backup copies of RDS, Aurora and EBS fail with AWS-managed KMS keys, because those keys can't be shared. Create every secret, and encrypt every source, on a customer-managed KMS key shared with the account that needs it.
- People through Identity Center, pipelines through roles. People get permission sets per account. CI gets OIDC federation to an IAM role in each account, never an Identity Center user and never a stored key.
- Know which account you're in. A consultant lives in many AWS accounts at once: each client, each environment, each role, and it's far too easy to run a command against production when you meant staging. switch-profile, my own tool, checks who you really are on every switch, and production accounts get a red PROD badge. Scripts and agents prefix every command with the profile and never rely on
[default]. - No root user in member accounts. Turn on centralised root access in IAM and remove root credentials from member accounts. New accounts are then created without them.
- Test a guardrail before it's everywhere. An SCP attached at the root that denies too much locks every member account out at once. Try it on a sandbox OU, move accounts in a few at a time, and keep SCPs in Pulumi, so a bad one is one revert away.
- Set up each new account. New accounts start below 1,000 concurrent Lambda executions: raise the quota before launch. An account that sends email needs SES production access and its pricing plan set: two CLI calls per region, in the runbook.
- Close accounts carefully. Closing an account suspends it for 90 days, then AWS deletes its vaults, even locked ones. Keep the backup account out of any clean-up, and deny it organizations:LeaveOrganization with an SCP.
Questions that change the answer
What can a leaked key or a wrong command reach today? If the answer includes production, production needs an account of its own.
Which workloads share a limit that one of them can break, such as SES's reputation or Lambda's concurrency pool? A limit with no fix inside the account calls for a wall.
Where do the backups live, and could the production account's credentials delete them? If they could, they're not a backup yet.
Who pays for which part of the bill? Teams that pay their own need their Savings Plans restricted, or Cost Categories.
Does a central security team vend dozens of accounts? That's when Control Tower earns its place.
Doesn't cover
Least-privilege policies inside an account. The walls limit how far a wrong policy reaches; they don't write the policies. The AWS entry has the method: the agent writes the policy from the code, and IAM Access Analyzer checks it.
Where application secrets live and how the code reads them: that's the Secrets Manager entry.
One AWS account per customer of a SaaS product: that's a tenancy question, not covered here.
Networks shared between accounts: not covered here.
Check your call
Decide before you open each answer.
A small startup runs its API, staging and a monthly newsletter on SES, all in one AWS account, with an IAM user key on each developer's laptop.
A management account, then dev, staging and prod accounts, with the newsletter in an account of its own, and Identity Center for every person instead of keys. Organizations costs nothing extra; what the walls buy is that a leaked key or a bad list import stops at one account.
A company keeps its Aurora snapshots and S3 versions in the production account. Its auditor asks what happens if an admin's credentials are stolen.
Whatever those credentials reach, they can delete, the snapshots included. Copy every recovery point to a locked vault in a separate backup account, on a customer-managed KMS key shared with it, keep point-in-time restore in production for 'undo the last hour', and deny organizations:LeaveOrganization on the backup account.
A platform team buys a Compute Savings Plan for production, then sees the discount land on a developer's test cluster in another account.
That's the default: the discount floats to any account in the organization. If teams pay their own bills, restrict the plan to the buying account, or group accounts with Cost Categories.
A central security team must vend dozens of accounts, with AWS's prebuilt controls.
Control Tower earns its place there. For a smaller company, Organizations, a handful of SCPs and Identity Center in code do the same job with less machinery.