Structure from day one#
Most teams start on AWS the same way: one account, signed in as the root user, with test, staging and production all deployed side by side. That works until a test script deletes the wrong resource, the bill can't tell you which environment spent what, or one leaked credential exposes everything at once.
The alternative is to design a secure, workable structure up front. On AWS that means AWS Organizations, a no-cost service that groups multiple accounts under central management with consolidated billing and centrally applied policies.
This guide covers how to design that structure in general terms: what each piece of AWS Organizations is, how to split accounts by environment and by workload, how to create a production OU and account step by step in the native AWS console, how to automate it with the AWS CLI and Terraform, and which guardrails, access controls and billing controls to switch on from the start.
Documentation: AWS · What is AWS Organizations ↗ · AWS · Organizing your AWS environment (whitepaper) ↗
Four concepts you need to keep apart#
The most common vocabulary mistake (the original version of this article made it too) is calling every folder an organization. AWS Organizations has distinct pieces:
- Organization: the whole entity. There is one per management account, and it contains every account.
- Management account: the account that created the organization. It pays the consolidated bill, creates and invites accounts, and manages policies. It is your most sensitive account.
- Root: the top container of the hierarchy. Every OU and account hangs off it, directly or indirectly.
- Organizational unit (OU): a folder under Root (or under another OU) that groups accounts sharing the same policies, such as production or sandbox.
- Member account: a regular AWS account that belongs to the organization. It is the real isolation boundary for resources, permissions and quotas.
The key idea: the account is the security and billing boundary; the OU is how you apply rules to a group of accounts at once.
Documentation: AWS · What is AWS Organizations ↗
The recommended structure: separate by environment#
AWS recommends a multi-account environment because each account isolates permissions, service quotas and cost. If staging and production live in different accounts, a mistake in staging cannot reach production, even when someone holds admin rights in staging.
For a team getting started, a sensible baseline is:
- The management account, with no workloads: organization, billing and policies only.
- A production OU with your production account (or accounts).
- A non-production OU for staging, QA and development.
- A sandbox OU for experiments, with tighter limits on services and spend.
As you grow, AWS's Organizing Your AWS Environment whitepaper describes further OUs such as Security (audit and log archive accounts), Infrastructure (networking and shared services), Workloads (split into production and non-production), Sandbox, Policy Staging and Suspended. You don't need all of them on day one, but it pays to pick names that fit that model.
| How you split | Upside | Downside |
|---|---|---|
| By environment (prod, staging, sandbox) | Clear security boundaries and simple SCPs per OU | Each OU grows quickly when there are many teams |
| By team or project | Straightforward per-team billing | Production and test end up in the same branch |
| Environment first, team below (nested OUs) | Isolation plus chargeback | More OUs and policies to maintain |
Inside each environment, the natural unit is the workload: one account per application or business domain per environment (for example shop-prod and shop-staging). Each team then gets its own permission and quota boundary, and per-account billing already tells you what each application costs in each environment. With only a few applications, starting with one production and one non-production account is perfectly fine; what matters is that the design lets you split later without starting over.
Root
├── management account (organization, billing and policies only)
├── OU Security
│ ├── log-archive (central logs, restricted access)
│ └── audit (security tooling, read-only access)
├── OU Workloads
│ ├── OU Prod
│ │ ├── shop-prod
│ │ └── payments-prod
│ └── OU NonProd
│ ├── shop-staging
│ └── payments-staging
└── OU Sandbox
└── sandbox-data-teamIf you'd rather not build it all by hand, AWS Control Tower sets up a landing zone on top of Organizations, with a Security OU, log archive and audit accounts and preconfigured controls. It is a solid option when you want a governed starting point; everything in this guide still applies.
Documentation: AWS · Benefits of using multiple AWS accounts ↗ · AWS · Recommended OUs and accounts ↗ · AWS · What is AWS Control Tower ↗
Step 1: open AWS Organizations#
Sign in to the console as a user of the account that will become the management account. Type Organizations in the top search bar and select AWS Organizations.
You'll land in one of two situations:
- If you have never created an organization, the console shows a Create an organization button. Clicking it turns your current account into the management account and creates Root.
- If an organization already exists, you go straight to the structure view (AWS accounts), where you create accounts and OUs.
The account that creates the organization stays its management account. If that account already runs production workloads, plan to move them into a member account over time rather than keep building there.
Documentation: AWS · What is AWS Organizations ↗ · AWS · Best practices for the management account ↗
Step 2: create the production organizational unit#
In the structure view, select Root, which will be the parent of the new OU, then choose Organizational unit > Create new.
In the form, type production in the Organizational unit name field and click Create organizational unit.
Back in the tree you'll notice two things:
- The production OU sits under Root, exactly where you created it.
- The OU is empty: it contains no accounts and no other OUs yet.
An empty OU costs nothing and does nothing on its own. It becomes useful once you place accounts and attach policies to it.
Documentation: AWS · Creating an organizational unit ↗
Step 3: create the production AWS account#
Now create the account that will live in that OU. Click Add an AWS account and keep the default option, Create an AWS account. Fill in the form:
- AWS account name: a practical choice is the OU's name or a workload-environment pattern (for example production or shop-prod). It's just a label and you can change it later.
- Email address of the account's owner: the root user email for the new account. It must be valid and not already used by another AWS account. An alias works; Gmail and many providers accept plus addresses such as [email protected]. A team distribution list is better than one person's inbox.
- IAM role name: leave the default, OrganizationAccountAccessRole. Organizations creates this role in the new account with administrator permissions and a trust relationship to the management account, so you can get in without root credentials.
Click Create AWS account. Creation is asynchronous and can take a few minutes; the console shows a notification and you can follow progress with View all pending creation requests.
When it finishes, the account appears in the tree at the first level, directly under Root. That is expected: accounts created from the console start in Root.
Documentation: AWS · Creating a member account ↗ · AWS · Accessing member accounts with OrganizationAccountAccessRole ↗
Step 4: move the account into the right OU#
For the account to inherit the production OU's policies, move it out of Root:
- Tick the box next to the production account in the tree.
- Choose Actions and, under AWS account, select Move.
- Pick the destination OU, production, and click Move AWS account.
Expand the production OU to confirm the account is now inside it. This also shows that the hierarchy isn't set in stone: you can move accounts between OUs later if you reorganize. Keep in mind that a moved account stops inheriting the old OU's policies and starts inheriting the new one's, so review the SCPs before moving anything that runs production.
Documentation: AWS · Moving accounts between OUs ↗
Automate it: AWS CLI and Terraform#
The console is the best way to understand the flow. To repeat it without mistakes (another account for staging, another for sandbox), keep it as code. Here are the same steps with the AWS CLI:
# Run with management account credentials
ROOT_ID=$(aws organizations list-roots --query 'Roots[0].Id' --output text)
# 1. Create the "production" OU under Root
OU_ID=$(aws organizations create-organizational-unit \
--parent-id "$ROOT_ID" --name production \
--query 'OrganizationalUnit.Id' --output text)
# 2. Create the member account (asynchronous: returns a request id)
REQ_ID=$(aws organizations create-account \
--account-name production \
--email [email protected] \
--role-name OrganizationAccountAccessRole \
--query 'CreateAccountStatus.Id' --output text)
# 3. Poll the status until it is SUCCEEDED
aws organizations describe-create-account-status \
--create-account-request-id "$REQ_ID"
# 4. Move the account from Root into the production OU
aws organizations move-account --account-id <ACCOUNT_ID> \
--source-parent-id "$ROOT_ID" --destination-parent-id "$OU_ID"With Terraform you declare the OU and the account, and create the account directly inside the OU using parent_id, which removes the move step entirely:
data "aws_organizations_organization" "this" {}
resource "aws_organizations_organizational_unit" "production" {
name = "production"
parent_id = data.aws_organizations_organization.this.roots[0].id
}
resource "aws_organizations_account" "production" {
name = "production"
email = "[email protected]"
role_name = "OrganizationAccountAccessRole"
# Created directly inside the OU: no move step needed
parent_id = aws_organizations_organizational_unit.production.id
lifecycle {
ignore_changes = [role_name]
}
}Documentation: Terraform AWS provider · aws_organizations_organizational_unit ↗ · Terraform AWS provider · aws_organizations_account ↗ · AWS · Creating a member account ↗
Guardrails: SCPs, access and the management account#
Separate accounts are the foundation; guardrails are what make the structure secure.
Service Control Policies (SCPs). You attach them to Root, an OU or an account, and they set the maximum permissions available in the affected accounts. They never grant permissions by themselves; they cap what IAM can grant. One important detail: SCPs do not affect users or roles in the management account, which is one more reason to keep workloads out of it.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyLeavingTheOrganization",
"Effect": "Deny",
"Action": "organizations:LeaveOrganization",
"Resource": "*"
}
]
}Access. Instead of sharing root credentials or creating IAM users in every account, use IAM Identity Center to give each person scoped access to only the accounts they need. Protect every account's root user with MFA and keep it out of day-to-day work.
Access. Instead of sharing root credentials or creating IAM users in every account, use IAM Identity Center (covered in the next section). Protect every account's root user with MFA and keep it out of day-to-day work.
Documentation: AWS · Service Control Policies (SCPs) ↗ · AWS · What is IAM Identity Center ↗ · AWS · Best practices for the management account ↗ · AWS Well-Architected · Security pillar ↗ · AWS · Example SCPs ↗
Access with IAM Identity Center#
With many accounts, creating IAM users in each one quickly becomes unmanageable. IAM Identity Center centralizes access: you connect an identity source (its built-in directory, Active Directory or an external provider such as Okta or Microsoft Entra ID), define permission sets and assign groups to specific accounts. Everyone signs in through a single portal and gets temporary credentials for the account and role they need.
- Enable IAM Identity Center from the organization's management account and choose the identity source.
- Consider delegating Identity Center administration to a member account so day-to-day work doesn't require signing in to the management account.
- Create permission sets per job function (for example AdministratorAccess for the platform team, ReadOnly for production lookups) rather than per person.
- Assign groups, not individual users, to each account with the right permission set: broad access in sandbox and staging, narrow access in production.
data "aws_ssoadmin_instances" "this" {}
locals {
sso_instance_arn = tolist(data.aws_ssoadmin_instances.this.arns)[0]
}
# Permission set: a reusable bundle of permissions for many accounts
resource "aws_ssoadmin_permission_set" "read_only" {
name = "ReadOnly"
instance_arn = local.sso_instance_arn
session_duration = "PT4H"
}
resource "aws_ssoadmin_managed_policy_attachment" "read_only" {
instance_arn = local.sso_instance_arn
permission_set_arn = aws_ssoadmin_permission_set.read_only.arn
managed_policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}
# Assignment: the "developers" group gets read-only access to production
resource "aws_ssoadmin_account_assignment" "developers_prod" {
instance_arn = local.sso_instance_arn
permission_set_arn = aws_ssoadmin_permission_set.read_only.arn
principal_type = "GROUP"
principal_id = var.developers_group_id
target_type = "AWS_ACCOUNT"
target_id = aws_organizations_account.production.id
}Documentation: AWS · Getting started with IAM Identity Center ↗ · AWS · Permission sets ↗ · AWS · Delegated administration for IAM Identity Center ↗ · Terraform AWS provider · aws_ssoadmin_permission_set ↗ · Terraform AWS provider · aws_ssoadmin_account_assignment ↗
Billing: one bill, costs per account#
Organizations turns on consolidated billing: the management account pays a single bill that adds up usage from every member account. That is the practical payoff of splitting by account: the cost of each environment and workload shows up broken down without having to tag every resource perfectly.
- Group by linked account in Cost Explorer to see spend per environment and application.
- Activate cost allocation tags (for example team or project) from the management account to break down costs inside a shared account. Tags only show up in reports after activation.
- Create per-account budgets with AWS Budgets, especially for sandbox, with alerts before the limit is reached.
- By default, Reserved Instance and Savings Plans discounts are shared across the organization's accounts; you can turn off sharing per account if the savings must be attributed to a specific team.
Documentation: AWS · Consolidated billing ↗ · AWS · Cost allocation tags ↗ · AWS · Managing costs with AWS Budgets ↗ · AWS · Turning off RI and Savings Plans discount sharing ↗
Structure checklist#
- The management account runs no workloads.
- Production lives in its own account inside a production OU.
- Staging, QA and sandbox sit in accounts and OUs separate from production.
- Each account uses a valid, unique team email and its root user has MFA.
- People reach accounts through IAM Identity Center or OrganizationAccountAccessRole, never shared root credentials.
- At least one baseline SCP is attached, and it was tested in a non-production OU first.
- The structure lives in code (CLI or Terraform) so you can repeat it.
- Each workload has its own account per environment, or the design lets you split it later without rebuilding.
- Per-account budgets exist and the cost allocation tags you rely on are activated.
With structure designed in from the start, adding a new environment stops being a project and becomes a small change. It is a foundation that scales as teams and projects grow.
Documentation: AWS · Recommended OUs and accounts ↗
Sources and scope
Documentation checked on September 25, 2026. Examples and decision criteria are editorial proposals; adapt them to your application's contract and validate them in an authorized test environment.
- AWS · What is AWS Organizations ↗
- AWS · Organizing your AWS environment (whitepaper) ↗
- AWS · Benefits of using multiple AWS accounts ↗
- AWS · Recommended OUs and accounts ↗
- AWS · What is AWS Control Tower ↗
- AWS · Best practices for the management account ↗
- AWS · Creating an organizational unit ↗
- AWS · Creating a member account ↗
- AWS · Accessing member accounts with OrganizationAccountAccessRole ↗
- AWS · Moving accounts between OUs ↗
- Terraform AWS provider · aws_organizations_organizational_unit ↗
- Terraform AWS provider · aws_organizations_account ↗
- AWS · Service Control Policies (SCPs) ↗
- AWS · What is IAM Identity Center ↗
- AWS Well-Architected · Security pillar ↗
- AWS · Example SCPs ↗
- AWS · Getting started with IAM Identity Center ↗
- AWS · Permission sets ↗
- AWS · Delegated administration for IAM Identity Center ↗
- Terraform AWS provider · aws_ssoadmin_permission_set ↗
- Terraform AWS provider · aws_ssoadmin_account_assignment ↗
- AWS · Consolidated billing ↗
- AWS · Cost allocation tags ↗
- AWS · Managing costs with AWS Budgets ↗
- AWS · Turning off RI and Savings Plans discount sharing ↗
Compare cloud options
Review pricing, limits, conditions and sources for each option (in Spanish).
Open comparison