Why Multiple AWS Accounts?
In production environments, running everything in a single AWS account is a security and operational risk. Multi-account strategies provide blast radius isolation, billing separation, and fine-grained access control.
Real-World Analogy: Running dev, staging, and prod in one AWS account is like keeping your personal and business finances in the same bank account — it works until something goes wrong, and then it’s a disaster to untangle.
The Problem with Single Accounts
| Risk |
Example |
Impact |
| Blast radius |
Dev mistake deletes prod database |
Catastrophic |
| Cost confusion |
Can’t separate dev vs prod spending |
Budget chaos |
| Permission creep |
Dev team has prod access |
Security breach |
| Service limits |
Dev consumes all EC2 limits |
Prod can’t scale |
| Compliance |
Audit scope includes all environments |
Expensive audits |
AWS Organizations
AWS Organizations lets you manage multiple AWS accounts from a single management account.
┌──────────────────────────────────────────────────────────────┐
│ AWS Organizations │
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Management Account (Root) ││
│ │ - Billing consolidation ││
│ │ - Organization policies ││
│ │ - NO workloads here ││
│ └───────────────┬─────────────────────────────────────────┘│
│ │ │
│ ┌──────────────┼──────────────┐ │
│ │ │ │ │
│ ┌─┴──────┐ ┌───┴────┐ ┌────┴─────┐ │
│ │Security │ │Workload│ │Sandbox │ ← OUs │
│ │ OU │ │ OU │ │ OU │ │
│ └────┬────┘ └───┬────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌────┴────┐ ┌────┴────────┐ ┌┴────────┐ │
│ │Log │ │Dev Staging │ │Developer │ │
│ │Archive │ │Prod │ │Sandboxes │ │
│ │Security │ │ │ │ │ │
│ │Tooling │ │ │ │ │ │
│ └─────────┘ └─────────────┘ └──────────┘ │
└──────────────────────────────────────────────────────────────┘
Recommended Account Structure
Minimum Viable Multi-Account (Startups)
| Account |
Purpose |
Who Uses It |
| Management |
Billing, Organizations |
Account admins only |
| Security |
CloudTrail logs, GuardDuty, Security Hub |
Security team |
| Dev |
Development workloads |
Developers |
| Prod |
Production workloads |
CI/CD pipelines |
Enterprise Account Structure
| OU |
Accounts |
Purpose |
| Security OU |
Log Archive, Security Tooling, Audit |
Centralized security |
| Infrastructure OU |
Networking, Shared Services |
Transit Gateway, DNS |
| Workloads OU |
Dev, Staging, Prod (per team) |
Application workloads |
| Sandbox OU |
Individual developer accounts |
Experimentation |
| Suspended OU |
Decommissioned accounts |
Account graveyard |
Setting Up AWS Organizations
# Create the organization
$ aws organizations create-organization --feature-set ALL
{
"Organization": {
"Id": "o-abc123",
"MasterAccountId": "111111111111"
}
}
# Create Organizational Units
$ aws organizations create-organizational-unit \
--parent-id r-root \
--name "Security"
{
"OrganizationalUnit": {
"Id": "ou-security",
"Name": "Security"
}
}
$ aws organizations create-organizational-unit --parent-id r-root --name "Workloads"
$ aws organizations create-organizational-unit --parent-id r-root --name "Sandbox"
# Create member accounts
$ aws organizations create-account \
--email prod-aws@company.com \
--account-name "Production"
{
"CreateAccountStatus": {
"Id": "car-abc123",
"AccountId": "222222222222",
"State": "IN_PROGRESS"
}
}
# Move account to correct OU
$ aws organizations move-account \
--account-id 222222222222 \
--source-parent-id r-root \
--destination-parent-id ou-workloads
Service Control Policies (SCPs)
SCPs set maximum permission boundaries for all accounts in an OU.
Deny Leaving the Organization
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyLeaveOrg",
"Effect": "Deny",
"Action": "organizations:LeaveOrganization",
"Resource": "*"
}]
}
Restrict Regions
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyNonApprovedRegions",
"Effect": "Deny",
"NotAction": [
"iam:*",
"organizations:*",
"support:*",
"sts:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["us-east-1", "us-west-2", "eu-west-1"]
}
}
}]
}
Deny Root User Access (Non-Management Accounts)
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyRootUser",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::*:root"
}
}
}]
}
# Apply SCP to an OU
$ aws organizations create-policy \
--name "DenyRootAccess" \
--description "Deny root user in member accounts" \
--type SERVICE_CONTROL_POLICY \
--content file://deny-root.json
$ aws organizations attach-policy \
--policy-id p-abc123 \
--target-id ou-workloads
AWS Control Tower
Control Tower automates multi-account setup with best practices built in.
| Feature |
What It Does |
| Landing Zone |
Pre-configured multi-account environment |
| Guardrails |
Preventive and detective controls |
| Account Factory |
Self-service account creation |
| Dashboard |
Compliance visibility |
Control Tower vs Manual Setup
| Aspect |
Manual (Organizations) |
Control Tower |
| Setup time |
Days to weeks |
Hours |
| Best practices |
You define them |
Built-in |
| Account creation |
CLI/Console |
Account Factory |
| Compliance |
Custom monitoring |
Automatic guardrails |
| Drift detection |
Custom |
Built-in |
| Best for |
Custom requirements |
Standard enterprise |
Cross-Account Access Patterns
Pattern 1: IAM Role Assumption
# In the target account (Prod), create a role
$ aws iam create-role \
--role-name CrossAccountDeployRole \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "deploy-2026"
}
}
}]
}'
# From the source account, assume the role
$ aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/CrossAccountDeployRole \
--role-session-name deploy-session \
--external-id deploy-2026
Pattern 2: Resource-Based Policies
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "CrossAccountS3Access",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:role/CI-CD-Role"
},
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::prod-artifacts/*"
}]
}
Consolidated Billing
| Feature |
Benefit |
| Single bill |
One invoice for all accounts |
| Volume discounts |
Combined usage gets better pricing |
| Reserved Instance sharing |
RI benefits apply across accounts |
| Cost allocation tags |
Track spending per team/project |
Common Mistakes
| Mistake |
Impact |
Prevention |
| Running workloads in management account |
Security risk |
Use member accounts only |
| No SCPs |
Accounts can do anything |
Apply restrictive SCPs from day one |
| Shared VPCs without planning |
Networking complexity |
Design CIDR ranges upfront |
| No centralized logging |
Can’t investigate incidents |
Set up Log Archive account first |
| Manual account creation |
Inconsistent setups |
Use Account Factory or IaC |
Next → Well-Architected Framework