How to Set Up AWS Organizations to Manage Multiple Accounts
When a company outgrows a single AWS account — dev workloads sharing blast radius with production, billing impossible to attribute, security policies applied inconsistently — the answer is almost always AWS Organizations. Setting up separate accounts for dev, staging, and production sounds straightforward, but the real value comes from understanding how Organizational Units, Service Control Policies, and consolidated billing interact before you start moving resources.
TL;DR: AWS Organizations Multi-Account Setup
| Concern | AWS Organizations Feature | Scope |
|---|---|---|
| Centralized billing | Consolidated billing (automatic) | Organization root |
| Environment isolation | Separate accounts per env | Account level |
| Policy guardrails | Service Control Policies (SCPs) | OU or account level |
| Account provisioning | AWS Organizations API / Control Tower | Management account |
| Cross-account access | IAM roles with trust policies | Member account |
How AWS Organizations Works
AWS Organizations is a global service managed from a single management account (formerly called the master account). Every other account you create or invite becomes a member account. The management account pays all bills — member accounts have no independent billing relationship with AWS unless you explicitly detach them.
The hierarchy looks like this: a single Root sits at the top, below which you create Organizational Units (OUs). OUs are just containers — they hold member accounts and can be nested up to five levels deep. Policies attached to an OU apply to every account inside it, including accounts in child OUs. That inheritance model is what makes OUs worth understanding before you create your first one.
Service Control Policies (SCPs) are the primary guardrail mechanism. An SCP does not grant permissions — it defines the maximum permissions any principal in the affected account can have. Even if an IAM policy in a member account allows an action, an SCP that denies it wins. This is the mechanism you use to prevent production accounts from disabling CloudTrail, or to restrict which AWS regions member accounts can operate in.
(Billing & Governance)"] InfraOU["Infrastructure OU
(Networking, Logging)"] WorkloadsOU["Workloads OU
(SCP: Region Restriction)"] DevOU["Dev OU
(Relaxed SCPs)"] StagingOU["Staging OU
(Moderate SCPs)"] ProdOU["Prod OU
(Strict SCPs)"] DevAcc["Dev Account"] StagingAcc["Staging Account"] ProdAcc["Prod Account"] Root --> MgmtOU Root --> InfraOU Root --> WorkloadsOU WorkloadsOU --> DevOU WorkloadsOU --> StagingOU WorkloadsOU --> ProdOU DevOU --> DevAcc StagingOU --> StagingAcc ProdOU --> ProdAcc
- Root — the top of the hierarchy. SCPs attached here apply to every account in the organization.
- Infrastructure OU — holds shared services like networking and logging accounts, isolated from workload accounts.
- Workloads OU — parent container for environment-specific OUs. SCPs here apply to all environments.
- Dev / Staging / Prod OUs — each holds one or more accounts for that environment. Prod gets stricter SCPs than Dev.
- Management Account — sits outside workload OUs. Never deploy application workloads here.
Step 1: Enable AWS Organizations in the Management Account
Before anything else, decide which account becomes the management account. This cannot be changed after the organization is created. Use a dedicated account with no application workloads — the management account has elevated trust across the entire organization and should be treated accordingly.
# Enable AWS Organizations (creates the organization with ALL features enabled)
aws organizations create-organization --feature-set ALL
The --feature-set ALL flag enables both consolidated billing and policy-based features including SCPs. If you choose CONSOLIDATED_BILLING only, you cannot attach SCPs later without migrating — start with ALL.
# Verify the organization was created and note the root ID
aws organizations list-roots
The root ID (format: r-xxxx) is required for subsequent OU creation commands. Note it now.
Step 2: Create the OU Structure
Design your OU hierarchy before creating accounts. Changing an account's OU later is possible but requires re-evaluating which SCPs apply — easier to get the structure right first.
# Create the top-level Workloads OU under root
aws organizations create-organizational-unit \
--parent-id r-xxxx \
--name Workloads
# Create environment OUs under Workloads
# Replace ou-xxxx-yyyyyyyy with the OU ID returned from the previous command
aws organizations create-organizational-unit \
--parent-id ou-xxxx-yyyyyyyy \
--name Dev
aws organizations create-organizational-unit \
--parent-id ou-xxxx-yyyyyyyy \
--name Staging
aws organizations create-organizational-unit \
--parent-id ou-xxxx-yyyyyyyy \
--name Prod
# List OUs under the Workloads OU to confirm
aws organizations list-organizational-units-for-parent \
--parent-id ou-xxxx-yyyyyyyy
Step 3: Create or Invite Member Accounts
You have two paths: create new accounts directly from the management account, or invite existing accounts. For a greenfield setup, creating accounts is cleaner — each new account gets an IAM role (OrganizationAccountAccessRole by default) that the management account can assume immediately.
# Create a new member account for the Dev environment
aws organizations create-account \
--email dev-aws@yourcompany.com \
--account-name "Company-Dev"
# Check account creation status (it's async — poll until State is SUCCEEDED)
aws organizations describe-create-account-status \
--create-account-request-id car-xxxxxxxxxxxxxxxx
Repeat for Staging and Prod with distinct email addresses. AWS requires a unique email per account — use email aliases if your domain supports them (e.g., aws+prod@yourcompany.com).
Step 4: Move Accounts into the Correct OUs
Newly created accounts land in the Root by default. Move them into the appropriate environment OU so that OU-level SCPs take effect.
# Move the Dev account into the Dev OU
# Replace 111111111111 with the actual Dev account ID
aws organizations move-account \
--account-id 111111111111 \
--source-parent-id r-xxxx \
--destination-parent-id ou-xxxx-devouId
# Verify the account is now in the correct OU
aws organizations list-accounts-for-parent \
--parent-id ou-xxxx-devouId
Step 5: Apply Service Control Policies as Security Guardrails
SCPs are where the real operational value of Organizations shows up. The default SCP attached to every OU and account is FullAWSAccess — it allows everything, meaning SCPs are additive denials layered on top of IAM. You write SCPs as deny lists or allow lists depending on your posture.
A common production guardrail: prevent anyone in the Prod account from disabling CloudTrail, regardless of their IAM permissions.
🔽 Click to expand: Prod SCP — Deny CloudTrail Disable
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyCloudTrailDisable",
"Effect": "Deny",
"Action": [
"cloudtrail:DeleteTrail",
"cloudtrail:StopLogging",
"cloudtrail:UpdateTrail"
],
"Resource": "*"
}
]
}
# Create the SCP
aws organizations create-policy \
--name DenyCloudTrailDisable \
--description 'Prevents disabling CloudTrail in Prod' \
--type SERVICE_CONTROL_POLICY \
--content file://deny-cloudtrail-disable.json
# Attach the SCP to the Prod OU
# Replace p-xxxxxxxx with the policy ID returned above
aws organizations attach-policy \
--policy-id p-xxxxxxxx \
--target-id ou-xxxx-prodouId
# Verify the policy is attached
aws organizations list-policies-for-target \
--target-id ou-xxxx-prodouId \
--filter SERVICE_CONTROL_POLICY
Another common guardrail: restrict all accounts in the Workloads OU to specific AWS regions. This prevents accidental resource creation in regions outside your compliance boundary.
🔽 Click to expand: Region Restriction SCP
{
"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"
]
}
}
}
]
}
Note the NotAction pattern — global services like IAM and STS are not region-scoped, so they must be excluded from region-restriction SCPs or you will break cross-account role assumption. This is a non-obvious interaction that breaks setups silently if missed.
Step 6: Set Up Cross-Account Access with IAM Roles
With accounts isolated, your engineers need a way to access them. The pattern is: assume a role in the target account from your identity provider or from the management account. The OrganizationAccountAccessRole created automatically in new member accounts gives the management account full admin access — useful for bootstrapping, but you should create least-privilege roles for day-to-day use.
# From the management account, assume the OrganizationAccountAccessRole in Dev
# to bootstrap the account (replace 111111111111 with Dev account ID)
aws sts assume-role \
--role-arn arn:aws:iam::111111111111:role/OrganizationAccountAccessRole \
--role-session-name BootstrapDev
For ongoing developer access, create a role in each member account with a trust policy pointing to your identity account or IAM Identity Center. Avoid using the OrganizationAccountAccessRole for routine operations — it has full admin permissions.
🔽 Click to expand: Least-privilege cross-account role trust policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::MANAGEMENT_ACCOUNT_ID:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}
Consolidated Billing: What Actually Happens
Consolidated billing is automatic once accounts join the organization — no configuration required. All member account charges roll up to the management account. The practical benefit beyond a single invoice is Reserved Instance and Savings Plans sharing: RIs purchased in any account can cover usage in other accounts within the organization, subject to the sharing settings.
# List all accounts in the organization to verify billing consolidation scope
aws organizations list-accounts
Cost allocation by account is visible in AWS Cost Explorer. Tag accounts with environment and team metadata to make per-environment cost attribution clean.
# Tag the Prod account for cost attribution
aws organizations tag-resource \
--resource-id 333333333333 \
--tags Key=Environment,Value=Production Key=Team,Value=Platform
Experience Signal: The SCP That Broke Production Deployments
A team applied a region-restriction SCP to the Prod OU using Action (deny list) instead of NotAction. The SCP explicitly denied all actions in non-approved regions. What they missed: their CI/CD pipeline was calling sts:GetCallerIdentity as a health check before every deployment. STS is a global service — the call was being evaluated against us-east-1 even though the pipeline ran in eu-west-1. The SCP blocked it.
The symptom was deployment pipelines failing at the authentication step with AccessDenied, but the IAM role permissions were correct. CloudTrail showed the deny, but the SCP evaluation context wasn't immediately obvious because the engineers were looking at IAM policies, not SCPs.
The fix was switching to the NotAction pattern shown above — explicitly excluding global service APIs from the region restriction rather than trying to enumerate every regional action. The lesson: when you see AccessDenied on an action that IAM clearly allows, check SCP evaluation in CloudTrail before touching IAM.
# Check CloudTrail for SCP-related denials
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=GetCallerIdentity \
--start-time 2024-01-01T00:00:00Z \
--end-time 2024-01-02T00:00:00Z
IAM Policy for Organizations Management Operations
The management account user or role performing Organizations setup needs explicit permissions. Read/List actions on Organizations require Resource: "*" — the Service Authorization Reference confirms these actions do not support resource-level restrictions.
🔽 Click to expand: IAM policy for Organizations setup
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "OrganizationsSetup",
"Effect": "Allow",
"Action": [
"organizations:CreateOrganization",
"organizations:CreateOrganizationalUnit",
"organizations:CreateAccount",
"organizations:MoveAccount",
"organizations:CreatePolicy",
"organizations:AttachPolicy",
"organizations:ListRoots",
"organizations:ListOrganizationalUnitsForParent",
"organizations:ListAccountsForParent",
"organizations:ListAccounts",
"organizations:ListPoliciesForTarget",
"organizations:DescribeCreateAccountStatus",
"organizations:TagResource"
],
"Resource": "*"
}
]
}
How to Set Up AWS Organizations: Decision Points Summary
OrganizationAccountAccessRole auto-created"] InviteAcc["Invite existing accounts
Manual role setup required"] Q3{"Human access at scale?"} IAMIdentityCenter["Enable IAM Identity Center"] IAMRoles["Use cross-account IAM roles"] Q4{"Automated account vending?"} ControlTower["Evaluate AWS Control Tower"] ManualOU["Manage OUs and SCPs manually"] Start --> Q1 Q1 -->|"Yes"| FeatureAll Q1 -->|"No"| FeatureBilling FeatureAll --> Q2 FeatureBilling --> Q2 Q2 -->|"New"| CreateAcc Q2 -->|"Existing"| InviteAcc CreateAcc --> Q3 InviteAcc --> Q3 Q3 -->|"Yes"| IAMIdentityCenter Q3 -->|"No"| IAMRoles IAMIdentityCenter --> Q4 IAMRoles --> Q4 Q4 -->|"Yes"| ControlTower Q4 -->|"No"| ManualOU
- Start by confirming whether you need SCP enforcement — if yes, you must enable ALL features, not just consolidated billing.
- Existing accounts can be invited, but they require manual acceptance and the
OrganizationAccountAccessRoleis not created automatically for invited accounts. - Control Tower is worth evaluating if you want pre-built guardrails, account vending, and an audit trail — it builds on Organizations but adds significant automation.
- IAM Identity Center (formerly SSO) integrates directly with Organizations and is the recommended path for human access to member accounts at scale.
Wrap-Up and Next Steps
Setting up AWS Organizations for dev, staging, and production isolation is a foundational decision — the OU structure and SCP design you choose now will constrain or enable everything built on top. Get the hierarchy right before creating accounts, enable ALL features from the start, and treat the management account as infrastructure, not a workspace.
From here, the natural next steps are enabling AWS IAM Identity Center for centralized human access, integrating AWS Config with organization-wide aggregators for compliance visibility, and evaluating AWS Control Tower if you want automated account vending with pre-built guardrails.
- AWS Organizations Getting Started — Official Documentation
- Service Control Policies — Official Documentation
- AWS Control Tower — Official Documentation
Glossary
| Term | Definition |
|---|---|
| Management Account | The AWS account that creates and owns the organization. Pays consolidated bills and can apply SCPs to all member accounts. |
| Organizational Unit (OU) | A container within the organization hierarchy that holds accounts or other OUs. Policies attached to an OU apply to all accounts within it. |
| Service Control Policy (SCP) | An Organizations policy type that defines the maximum permissions available to accounts in the affected OU or account. Does not grant permissions — only restricts them. |
| Consolidated Billing | A feature of Organizations where all member account charges are billed to the management account, enabling RI sharing and unified cost visibility. |
| OrganizationAccountAccessRole | An IAM role automatically created in new member accounts, with a trust policy allowing the management account to assume it. Used for initial account bootstrapping. |
Comments
Post a Comment