Skip to content
ExponaBLOG
AWS FOR DEVELOPERS · DAY 003 / 100

Use multiple AWS accounts from day one, explained simply

One account for everything doesn't age well.

Expona Admin7 min read

Use multiple AWS accounts from day one

I've watched teams deploy their first microservice to a single AWS account, assuring themselves they'll split things up later. Spoiler: they rarely do, and by the time they realize the mistake, they're managing dozens of services with zero isolation, shared credentials across environments, and a security audit waiting to happen. Use multiple AWS accounts from day one because separating your infrastructure by environment and business unit isn't a nice-to-have—it's foundational to operating at any real scale.

Why a single account fails you

Before diving into the solution, let's be honest about what happens when you skip this step. A single account gives you one blast radius. A misconfigured security group, a rogue Lambda, a billing spike from a runaway resource—any of these impacts everything. You can't isolate blast radius, you can't enforce different policies per environment, and you can't easily audit who touched what. More practically, your staging database might accidentally get hit by a production data pipeline. Your junior engineer's experimental cluster consumes the same budget pool as your payment service.

I worked on a trading platform where we kept dev and production in one account for the first six months. When we finally migrated to separate accounts, we discovered that our dev team had accidentally created 47 Elasticsearch clusters for testing. In production. The cleanup took two weeks and taught us an expensive lesson about isolation.

Separate dev, staging, and production

The simplest multi-account strategy is environment-based separation: one account for development, one for staging, one for production. This gives you hard boundaries that no misconfiguration can cross.

Development account: This is your sandbox. Your team experiments here without fear. IAM policies can be loose (within reason). You're testing new services, new libraries, new architecture ideas. Resources spin up and tear down constantly. Billing here should be predictable because you're not keeping long-running infrastructure.

Staging account: This mirrors production as closely as possible. Your infrastructure-as-code runs here first. Your deployment pipeline tests against real AWS services. Your team validates scaling behavior, database migrations, and infrastructure changes before they touch production. Access is tighter than dev but looser than production. Everyone can debug here, but not everyone deploys.

Production account: Locked down hard. Minimal IAM permissions. Detailed logging and monitoring. Your CI/CD pipeline is the only thing that deploys here. A human might authorize a deployment, but they don't SSH into instances or manually patch databases. CloudTrail logs everything. This account is read-only except for your deployment service.

Here's what your account structure might look like:

bash
aws-dev-account:        111111111111
aws-staging-account:    222222222222
aws-prod-account:       333333333333

Your deployment pipeline knows these account IDs and assumes a role in each one with appropriate permissions. A developer's local AWS CLI can access dev and staging freely but cannot assume any role in production—that requires going through your CI/CD system.

AWS Organizations for central billing

Managing three separate AWS accounts means three separate sign-ups, three separate payment methods, three separate bills. Unless you use AWS Organizations, which consolidates billing across all your member accounts under a single payer account while keeping the accounts independent.

Here's how it works: you create a payer account (sometimes called the management account) and then invite your dev, staging, and production accounts to join an organization under that payer. All charges roll up to the payer account's bill, you get volume discounts applied across all accounts, and you see a single invoice each month.

The payer account itself should do almost nothing. It's purely for billing, organizational structure, and applying policies. You don't deploy applications there. You don't run databases there. You create it, set up the organization, add member accounts, and then you mostly leave it alone.

Setting up Organizations takes about ten minutes:

  1. Log into your payer account (the one that will receive all the bills).
  2. Open AWS Organizations and create an organization.
  3. From your dev account, open AWS Organizations and request to join the organization using the payer's organization ID.
  4. Switch back to your payer account and accept the invitation.
  5. Repeat for staging and production.

Now your payer account can see spending across all accounts in real time. You can set up cost anomaly detection to alert you if spending spikes unexpectedly. You can use cost allocation tags to track spending by team or project even across account boundaries. And each member account still has independent access control—your production team doesn't need AWS credentials for the billing payer account.

Service control policies as guardrails

Once your accounts are organized, you need rules to prevent people from making catastrophic mistakes. Service Control Policies (SCPs) are AWS's way of setting organization-wide guardrails. They're like IAM policies but they apply at the account level and override individual IAM policies—even the Administrator policy can't bypass an SCP.

Common SCPs I've used:

  • Prevent accidental deletion: Deny DeleteDB* actions in staging and dev unless explicitly allowed. Your team shouldn't be able to nuke a database without going through proper channels.
  • Enforce encryption: Deny any S3 PutObject that doesn't include server-side encryption. Every backup, every artifact, every log must be encrypted.
  • Restrict regions: Deny any action outside your approved regions (say, us-east-1 and eu-west-1). Prevents multi-region sprawl and keeps compliance simpler.
  • Require MFA for sensitive operations: Deny termination of RDS instances unless the principal authenticated with MFA in the last hour.
  • Quarantine production account: Deny all service changes in production except from your CI/CD role. Everything else gets read-only access.

Here's a simple SCP that prevents anyone from deleting DynamoDB tables unless they're in the operations role:

bash
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "NotPrincipal": {
        "AWS": "arn:aws:iam::333333333333:role/operations-role"
      },
      "Action": [
        "dynamodb:DeleteTable"
      ],
      "Resource": "*"
    }
  ]
}

You'd attach this policy to your production account via Organizations. Now even an admin user in that account cannot delete a DynamoDB table unless they're using the operations-role. If someone tries, AWS denies it silently.

Warning: SCPs are powerful and can lock you out if misconfigured. Always test them in dev first. Always make sure you have at least one role that can modify SCPs (usually a root-level access) in case you need to recover.

Control Tower automates the setup

AWS Control Tower is the easy button for multi-account management. Instead of manually creating accounts, inviting them to Organizations, and writing SCPs, Control Tower does it all in one coherent system. It creates a landing zone—a pre-configured, multi-account environment with guardrails already in place.

When you set up Control Tower, it:

  • Creates an organization (if you don't have one).
  • Sets up a shared services account for things like logging and security scanning.
  • Creates an audit account for compliance and auditing.
  • Applies a standard set of guardrails (SCPs and Config rules) across all accounts.
  • Sets up centralized logging to CloudTrail, Config, and S3.
  • Gives you a dashboard to manage users and accounts from one place.

I used Control Tower on a SaaS platform and it saved us weeks of manual configuration. Instead of writing our own SCPs from scratch, we got a tested baseline. Instead of manually creating member accounts, we provisioned new ones through the Control Tower console in minutes.

The catch: Control Tower is opinionated. It enforces a certain structure and certain policies that you can't easily customize in the console. But for most teams, that's a feature, not a bug—it means you inherit AWS best practices by default.

Common mistakes

  • Using Organizations but treating member accounts like they're separate: Teams often forget they're one organization and create duplicate infrastructure, duplicate policies, or duplicate cost centers. Decide upfront how you'll structure your accounts and enforce it via SCPs.
  • Making the payer account do real work: I've seen teams deploy applications to the payer account to "save money" or keep things "centralized." That defeats the purpose. The payer account should only manage organization and billing.
  • Forgetting to enable CloudTrail organization-wide: You set up multiple accounts but don't turn on CloudTrail logging from day one. Six months later, you need to investigate a security incident and have zero logs. Enable organization-wide CloudTrail in your payer account immediately after setup.
  • Over-provisioning with too many accounts too early: While separation is important, don't create 20 accounts for 20 services if you have a small team. Start with dev, staging, production. Add more (like per-team accounts or per-customer accounts) only when you actually need the isolation.
  • Applying SCPs without testing: A poorly written SCP can block legitimate work. Always write and test SCPs in a dev organization first, then gradually roll them out.

Key takeaways

  • Separate your dev, staging, and production infrastructure into different AWS accounts from day one. It gives you isolation, safer experimentation, and clear blast radius boundaries.
  • Use AWS Organizations to consolidate billing across member accounts while keeping them independent. The payer account should do nothing but manage organization and billing.
  • Write Service Control Policies to enforce guardrails—prevent accidental deletions, require encryption, restrict regions, and lock down production. SCPs override any individual IAM policy.
  • Consider AWS Control Tower if you want a pre-built landing zone with guardrails and audit logging already configured. It's opinionated but saves weeks of manual setup.
  • Test everything in dev first. A misconfigured SCP or organization policy can lock you out of production if you're not careful.
ShareXLinkedInReddit

Found this useful? Support the writing.

Buy me a coffee
Written by
Expona Admin
Site administrator

Comments

Loading comments…

Leave a comment

Comments are reviewed before they appear. Be kind and stay on topic.

Related articles